ادغام ۱۲ کامیت ریموت (لایهٔ realtime روی WebSocket، حذف REST عمومی، رفع
باگهای صفحهٔ مدلها) با ۸ کامیت محلی (ارائهدهندهٔ agy + رفع فلو دعوت).
تنها کانفلیکت واقعی در `app/main.py` بود و ماهوی بود، نه متنی:
ریموت اپ عمومی را به «فقط /health + /api/ws» کاهش داده و همهٔ هندلرهای HTTP
را به اپ داخلی `interfaces/realtime/rpc_app.py` منتقل کرده است. بنابراین
روتر `invites` من نباید در اپ عمومی mount شود.
راهحل:
- `app/main.py`: فقط `health` و `realtime_router` میمانند؛ ایمپورتهای اضافی
حذف شدند (نسخهٔ ریموت).
- `interfaces/realtime/rpc_app.py`: روتر `invites` به اپ داخلی اضافه شد تا
`GET /api/invites/{token}` و `POST /api/invites/accept` از مسیر WS-RPC
قابل دسترس باشند.
`api.ts` و `contracts/index.ts` خودکار و بدون کانفلیکت ادغام شدند: کلاینت
`previewInvite`/`acceptInvite` حالا از `getRealtimeClient().rpc()` رد میشود،
پس هیچ تغییری در فراخوانیها لازم نبود.
رفع تست شکستهٔ ریموت: `src/test/version.test.tsx` مقدار `AppShell` را بدون
`RealtimeProvider` رندر میکرد و `useRealtime` استثنا میداد. حالا اسکلت
همانطور که در `app/layout.tsx` سیمکشی شده رندر میشود و سوکت در تست stub
شده است.
اعتبارسنجی روی درخت ادغامشده:
- بکاند ۲۷۰ تست سبز (شامل ۶ تست دعوت روی معماری جدید)؛ mypy تمیز.
- فرانت ۶۱ تست سبز؛ tsc و eslint تمیز.
- تأیید شد روترهای invite روی اپ داخلی RPC حاضرند و سطح عمومی تغییر نکرده.
نکته: ۵ خطای ruff در `tests/conftest.py`، `tests/test_error_log.py` و
`tests/test_realtime.py` از خود `origin/dev` میآیند و به این ادغام ربطی
ندارند؛ دستنخورده رها شدند.
The platform no longer exposes a public /api/* REST surface. The original
HTTP route handlers are preserved verbatim as the single source of truth
inside an internal, never-socket-bound FastAPI app (rpc_app), and are now
reached only via RPC-over-WebSocket dispatch.
- realtime router: anonymous connections allowed only to /api/auth/login
and /api/auth/signup; all other RPCs/subscribes refused until token auth.
- RPC dispatch re-injects the bearer token and X-Request-ID, then forwards
through httpx.ASGITransport against the internal app (no network hop).
- Public app now serves only /, /health, /health/ready and /api/ws;
docs/openapi disabled.
- Frontend: apiRequest routes /api/* to ws.rpc(); /health probes keep fetch.
RealtimeClient gains rpc() with id correlation, timeout and AbortSignal.
- Tests repointed to get_rpc_app(); anonymous-auth behaviour covered.
Result: zero REST on the public surface; 264 backend tests + frontend
typecheck pass.