| R4-HTTP-001 |
Real NDB+BFF channel readiness / HTTP+PG |
Dedicated ports/databases;GET /health/ready |
NDB signed ping and PG both up |
{"status":"ok","channelDb":"up","ndb":"up"} |
Pass |
http-integration-results.json;2026-10-06T16:29:26.804Z;#4复验范围 |
| R4-HTTP-002 |
Synthetic zero-contract empty baseline / HTTP+PG |
Fresh migration and seed;Read isolated ORM snapshot |
0 Registration, 0 Tasks, 0 Contracts |
{"registrations":[],"tasks":[],"contract_count":0} |
Pass |
http-integration-results.json;2026-10-06T16:29:26.804Z;#4复验范围 |
| R4-HTTP-003 |
Anonymous minutes write denied / HTTP+PG |
No JWT;PUT A minutes |
401 UNAUTHENTICATED, no mutation |
{"status":401,"data":{"error":{"code":"UNAUTHENTICATED","message":"请先登录"},"requestId":"6def3d9e-6172-415e-863e-151132724f73"}} |
Pass |
http-integration-results.json;2026-10-06T16:29:27.556Z;#4复验范围 |
| R4-HTTP-004 |
Unbound synthetic JWT denied / HTTP+PG |
User lacks phone/contact;PUT A minutes |
403 CONTACT_NOT_BOUND |
{"status":403,"data":{"error":{"code":"CONTACT_NOT_BOUND","message":"请先绑定客户联系人"},"requestId":"682e586e-8537-4a7a-95e8-eafc68a29d72"}} |
Pass |
http-integration-results.json;2026-10-06T16:29:27.558Z;#4复验范围 |
| R4-HTTP-005 |
Legacy subscription is not reservation / HTTP+PG |
Only old channel subscription seeded;GET A minutes |
JSON null, no NDB Task |
{"reservation":null,"taskCount":0} |
Pass |
http-integration-results.json;2026-10-06T16:29:27.567Z;#4复验范围 |
| R4-HTTP-006 |
A started free minutes-only created / HTTP+PG |
A started,0h,no contract;PUT A minutes |
reserved+unified Registration/Task |
{"id":"1","meetingId":"1","clientContactId":"2","taskId":"1","status":"reserved","createdAt":"2026-10-07T00:29:28.409211"} |
Pass |
http-integration-results.json;2026-10-06T16:29:28.357Z;#4复验范围 |
| R4-HTTP-007 |
A same-key retry reuses ids / HTTP+PG |
A reserved;Repeat PUT same key |
Same registration/task ids |
{"id":"1","meetingId":"1","clientContactId":"2","taskId":"1","status":"reserved","createdAt":"2026-10-07T00:29:28.409211"} |
Pass |
http-integration-results.json;2026-10-06T16:29:28.414Z;#4复验范围 |
| R4-HTTP-008 |
A authoritative GET preserves server naive microseconds / HTTP+PG |
A reserved after replay;GET A minutes |
same ids and exact createdAt string |
{"id":"1","meetingId":"1","clientContactId":"2","taskId":"1","status":"reserved","createdAt":"2026-10-07T00:29:28.409211"} |
Pass |
http-integration-results.json;2026-10-06T16:29:28.452Z;#4复验范围 |
| R4-HTTP-009 |
A concurrent natural retries on real PG / HTTP+PG |
A reserved; threaded real Backend;6 parallel PUT with distinct keys |
All same ids and only one Task |
{"responses":6,"registrationId":"1","taskId":"1","taskCount":1} |
Pass |
http-integration-results.json;2026-10-06T16:29:28.487Z;#4复验范围 |
| R4-HTTP-010 |
A minutes-only has no attendance projection / HTTP+PG |
A minutes requested only;GET A registration |
JSON null |
null |
Pass |
http-integration-results.json;2026-10-06T16:29:29.352Z;#4复验范围 |
| R4-HTTP-011 |
A absent myMeetings and present myMinutes / HTTP+PG |
A minutes-only;GET both lists |
Attendance empty; minutes contains A |
{"myMeetings":0,"myMinutes":1} |
Pass |
http-integration-results.json;2026-10-06T16:29:29.394Z;#4复验范围 |
| R4-HTTP-012 |
A minutes-only cannot obtain join link / HTTP+PG |
A already started;GET A join-link |
visible=false,joinUrl=null |
{"visible":false,"joinUrl":null,"reason":"REGISTRATION_REQUIRED"} |
Pass |
http-integration-results.json;2026-10-06T16:29:29.483Z;#4复验范围 |
| R4-HTTP-013 |
A cannot add attendance after start / HTTP+PG |
A started,minutes-only;POST A registration |
MEETING_NOT_OPEN without new Task |
{"status":409,"data":{"error":{"code":"MEETING_NOT_OPEN","message":"会议当前不可报名"},"requestId":"5f775969-8e2c-48fe-bd92-b16e7b15eb49"}} |
Pass |
http-integration-results.json;2026-10-06T16:29:29.527Z;#4复验范围 |
| R4-HTTP-014 |
B1 minutes first while not started / HTTP+PG |
B1 future,0h;PUT B1 minutes |
reserved |
{"id":"2","meetingId":"2","clientContactId":"2","taskId":"2","status":"reserved","createdAt":"2026-10-07T00:29:30.412283"} |
Pass |
http-integration-results.json;2026-10-06T16:29:30.361Z;#4复验范围 |
| R4-HTTP-015 |
B1 then attendance shares Registration/Task / HTTP+PG |
B1 minutes first;POST B1 registration + isolated snapshot |
same id/task, both flags |
{"projection":{"id":"2","meetingId":"2","status":"confirmed"},"record":{"id":2,"meeting_id":2,"client_contact_id":2,"task_id":2,"attend_requested":true,"minutes_requested":true,"status":"confirmed"}} |
Pass |
http-integration-results.json;2026-10-06T16:29:30.416Z;#4复验范围 |
| R4-HTTP-016 |
B1 future join link withheld / HTTP+PG |
B1 both intents before start;GET join-link |
visible=false |
{"visible":false,"joinUrl":null,"reason":"MEETING_NOT_OPEN"} |
Pass |
http-integration-results.json;2026-10-06T16:29:31.223Z;#4复验范围 |
| R4-HTTP-017 |
B2 attendance first while not started / HTTP+PG |
B2 future,0h;POST B2 registration |
confirmed |
{"id":"3","meetingId":"3","status":"confirmed"} |
Pass |
http-integration-results.json;2026-10-06T16:29:31.254Z;#4复验范围 |
| R4-HTTP-018 |
B2 then minutes shares Registration/Task / HTTP+PG |
B2 attend first;PUT B2 minutes + snapshot |
same id,task, both flags |
{"reservation":{"id":"3","meetingId":"3","clientContactId":"2","taskId":"3","status":"reserved","createdAt":"2026-10-07T00:29:31.297439"},"record":{"id":3,"meeting_id":3,"client_contact_id":2,"task_id":3,"attend_requested":true,"minutes_requested":true,"status":"confirmed"}} |
Pass |
http-integration-results.json;2026-10-06T16:29:31.301Z;#4复验范围 |
| R4-HTTP-019 |
Both intentions appear in separate lists / HTTP+PG |
A minutes-only,B1/B2 both;GET both my lists |
myMeetings=2,myMinutes=3 |
{"myMeetings":2,"myMinutes":3} |
Pass |
http-integration-results.json;2026-10-06T16:29:32.908Z;#4复验范围 |
| R4-HTTP-020 |
Future B1 cancel keeps minutes and Task / HTTP+PG |
B1 future,both;DELETE registration |
cancelled;same reserved minutes and ongoing Task |
{"registration":{"id":"2","meetingId":"2","status":"cancelled"},"reservation":{"id":"2","meetingId":"2","clientContactId":"2","taskId":"2","status":"reserved","createdAt":"2026-10-07T00:29:30.412283"},"taskStatus":"ongoing"} |
Pass |
http-integration-results.json;2026-10-06T16:29:32.989Z;#4复验范围 |
| R4-HTTP-021 |
Future B1 reattend reuses id/Task / HTTP+PG |
B1 cancelled but future;POST registration fresh key |
confirmed,same ids,3 Tasks total |
{"id":"2","meetingId":"2","status":"confirmed"} |
Pass |
http-integration-results.json;2026-10-06T16:29:33.910Z;#4复验范围 |
| R4-HTTP-022 |
Advance only isolated B fixtures to started / HTTP+PG |
B1/B2 future registration complete;Guarded synthetic ORM time update |
Only B1/B2 updated |
{"advanced":[2,3]} |
Pass |
http-integration-results.json;2026-10-06T16:29:34.732Z;#4复验范围 |
| R4-HTTP-023 |
Started attendee B1 obtains link / HTTP+PG |
B1 advanced,confirmed;GET join-link |
visible=true synthetic invalid-domain link |
{"visible":true,"joinUrl":"https://qa-meeting.example.invalid/join/B1_minutes_attend","reason":null}
|
Pass |
http-integration-results.json;2026-10-06T16:29:35.508Z;#4复验范围 |
| R4-HTTP-024 |
Started attendee B2 obtains link / HTTP+PG |
B2 advanced,confirmed;GET join-link |
visible=true |
{"visible":true,"joinUrl":"https://qa-meeting.example.invalid/join/B2_attend_minutes","reason":null}
|
Pass |
http-integration-results.json;2026-10-06T16:29:35.550Z;#4复验范围 |
| R4-HTTP-025 |
Started B1 cancel preserves minutes Task / HTTP+PG |
B1 started,both;DELETE registration + snapshot |
cancelled and minutes same ids/ongoing Task |
{"registration":{"id":"2","meetingId":"2","status":"cancelled"},"reservation":{"id":"2","meetingId":"2","clientContactId":"2","taskId":"2","status":"reserved","createdAt":"2026-10-07T00:29:30.412283"}} |
Pass |
http-integration-results.json;2026-10-06T16:29:35.586Z;#4复验范围 |
| R4-HTTP-026 |
Cancelled started B1 loses link / HTTP+PG |
B1 cancelled,minutes retained;GET join-link |
visible=false,no link |
{"visible":false,"joinUrl":null,"reason":"REGISTRATION_REQUIRED"} |
Pass |
http-integration-results.json;2026-10-06T16:29:36.486Z;#4复验范围 |
| R4-HTTP-027 |
Started B1 cannot restore attendance / HTTP+PG |
B1 cancelled after start;POST attend fresh key |
MEETING_NOT_OPEN,no extra Task |
{"status":409,"data":{"error":{"code":"MEETING_NOT_OPEN","message":"会议当前不可报名"},"requestId":"f261e04e-d31e-4dbc-ae31-145be5e9c02f"}} |
Pass |
http-integration-results.json;2026-10-06T16:29:36.520Z;#4复验范围 |
| R4-HTTP-028 |
Started B1 repeated minutes retained / HTTP+PG |
B1 cancelled attendee,minutes active;PUT minutes fresh key |
same reserved id/task |
{"id":"2","meetingId":"2","clientContactId":"2","taskId":"2","status":"reserved","createdAt":"2026-10-07T00:29:30.412283"} |
Pass |
http-integration-results.json;2026-10-06T16:29:37.344Z;#4复验范围 |
| R4-HTTP-029 |
Started B2 cancel preserves same minutes Task / HTTP+PG |
B2 opposite order;DELETE registration |
cancelled,same minutes id/task |
{"registration":{"id":"3","meetingId":"3","status":"cancelled"},"reservation":{"id":"3","meetingId":"3","clientContactId":"2","taskId":"3","status":"reserved","createdAt":"2026-10-07T00:29:31.297439"}} |
Pass |
http-integration-results.json;2026-10-06T16:29:37.390Z;#4复验范围 |
| R4-HTTP-030 |
All free Tasks remain zero and unique / HTTP+PG |
A/B1/B2 complete;Read isolated snapshot |
3 registrations,3 unique Tasks,0 contracts,all prices0 |
{"registrations":[{"id":1,"meeting_id":1,"client_contact_id":2,"task_id":1,"attend_requested":false,"minutes_requested":true,"status":"confirmed"},{"id":2,"meeting_id":2,"client_contact_id":2,"task_id":2,"attend_requested":true,"minutes_requested":true,"status":"cancelled"},{"id":3,"meeting_id":3,"client_contact_id":2,"task_id":3,"attend_requested":true,"minutes_requested":true,"status":"cancelled"}],"tasks":[{"id":1,"status":"ongoing","contract_id":null,"charge_total_hours":"0.0000","actual_price":"0.00","total_price":"0.00"},{"id":2,"status":"ongoing","contract_id":null,"charge_total_hours":"0.0000","actual_price":"0.00","total_price":"0.00"},{"id":3,"status":"ongoing","contract_id":null,"charge_total_hours":"0.0000","actual_price":"0.00","total_price":"0.00"}],"contract_count":0} |
Pass |
http-integration-results.json;2026-10-06T16:29:37.464Z;#4复验范围 |
| R4-HTTP-031 |
Synthetic paid no contract rejects without mutation / HTTP+PG |
D synthetic1h,no contracts;PUT D minutes |
NO_ACTIVE_CONTRACT,still3 Tasks |
{"status":409,"data":{"error":{"code":"NO_ACTIVE_CONTRACT","message":"当前客户暂无有效合同,请联系客户经理开通后再报名"},"requestId":"e5e32c49-8b3e-48f0-ad21-a43a50da7cde"}} |
Pass |
http-integration-results.json;2026-10-06T16:29:38.248Z;#4复验范围 |
| R4-HTTP-032 |
Real PG refusal outbox durable and deduplicated / HTTP+PG |
D denied;Repeat rejection+PG SELECT |
one pending row,not reservation |
[{"meeting_id":"4","state":"pending","attempts":0,"accepted_at":null}] |
Pass |
http-integration-results.json;2026-10-06T16:29:39.079Z;#4复验范围 |
| R4-HTTP-033 |
Refusal persists across real BFF restart and mock acceptance / HTTP+PG |
Outbox stored in real PG;Stop/restart BFF; bootstrap dispatch to mock13001 |
same row accepted once;no real email |
{"outbox":{"state":"accepted","attempts":1,"accepted_at":"2026-10-06T16:29:39.777Z"},"mockRequests":1,"realEmails":0} |
Pass |
http-integration-results.json;2026-10-06T16:29:39.132Z;#4复验范围 |
| R4-HTTP-034 |
Accepted refusal never becomes successful reservation / HTTP+PG |
D notice accepted by mock;GET D minutes;GET myMinutes;snapshot |
null,D absent,3 Tasks |
{"reservation":null,"myMinutes":3,"taskCount":3} |
Pass |
http-integration-results.json;2026-10-06T16:29:39.930Z;#4复验范围 |