mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-17 23:09:35 +00:00
chore(dealix): launch checklist, E2E port helper, OpenAPI path scan
- Document verify-launch, py/py-3, E2E, and port 3000 troubleshooting - Add scripts/kill-port-3000.ps1 for Playwright webServer conflicts - Increase Playwright webServer timeout to 180s - Extend verify_frontend_openapi_paths for template literals; empty allowlist - Commit Next routes.d.ts reference in next-env.d.ts after build Made-with: Cursor
This commit is contained in:
parent
fcdbc1f004
commit
67fcc35877
@ -2,19 +2,22 @@
|
|||||||
|
|
||||||
## 1. الكود والاختبارات
|
## 1. الكود والاختبارات
|
||||||
|
|
||||||
- [ ] `cd backend && py -m pytest tests -q` — يجب أن تمر كل الاختبارات.
|
- [ ] **اختبارات الباكند:** من `backend/` شغّل `python -m pytest tests -q` (مثل CI على Linux) أو على ويندوز إذا الأمر `python` غير موجود: `py -3 -m pytest tests -q`.
|
||||||
- [ ] `cd frontend && npm run lint && npm run build`.
|
- [ ] **بوابة موحّدة (موصى به):** من جذر `salesflow-saas`: `.\verify-launch.ps1` — يشغّل pytest + مزامنة التسويق + lint + build.
|
||||||
|
- [ ] `cd frontend && npm run lint && npm run build` (أو تُغطّى بواسطة `verify-launch.ps1`).
|
||||||
- [ ] من جذر `salesflow-saas`: `node scripts/sync-marketing-to-public.cjs` (يُشغَّل أيضاً تلقائياً قبل `npm run build`).
|
- [ ] من جذر `salesflow-saas`: `node scripts/sync-marketing-to-public.cjs` (يُشغَّل أيضاً تلقائياً قبل `npm run build`).
|
||||||
- [ ] (اختياري) من جذر `salesflow-saas`: `py scripts/verify_frontend_openapi_paths.py` — يطابق مسارات `/api/v1` الظاهرة حرفيًا في الفرونت مع OpenAPI.
|
- [ ] **E2E (Playwright):** بعد `npm run build`، حرّر المنفذ **3000** ثم من `frontend/`: `CI=true npm run test:e2e`. إن ظهر «port already in use» أو timeout على `webServer`: من جذر `salesflow-saas` شغّل `.\scripts\kill-port-3000.ps1` ثم أعد المحاولة.
|
||||||
|
- [ ] (اختياري) من جذر `salesflow-saas`: `py -3 scripts/verify_frontend_openapi_paths.py` (أو `python3 scripts/...`) — يطابق مسارات `/api/v1` في الفرونت مع OpenAPI (حرفيًا وفي قوالب مثل `` `${base}/api/v1/...` ``).
|
||||||
|
|
||||||
## 2. الخادم (API)
|
## 2. الخادم (API)
|
||||||
|
|
||||||
- [ ] تشغيل من **أحدث** كود في المستودع:
|
- [ ] تشغيل من **أحدث** كود في المستودع:
|
||||||
`cd backend && py -m uvicorn app.main:app --host 0.0.0.0 --port 8000`
|
`cd backend && python -m uvicorn app.main:app --host 0.0.0.0 --port 8000`
|
||||||
|
(ويندوز: `py -3 -m uvicorn app.main:app --host 0.0.0.0 --port 8000`)
|
||||||
- [ ] إذا ظهر **404** على `/api/v1/marketing/hub` أو `/api/v1/strategy/summary` فالعملية غالباً **قديمة** — أعد تشغيل `uvicorn` بعد `git pull`.
|
- [ ] إذا ظهر **404** على `/api/v1/marketing/hub` أو `/api/v1/strategy/summary` فالعملية غالباً **قديمة** — أعد تشغيل `uvicorn` بعد `git pull`.
|
||||||
- [ ] اختبار HTTP:
|
- [ ] اختبار HTTP (من مجلد `backend/`):
|
||||||
`py scripts/full_stack_launch_test.py --http-only --soft-ready`
|
`py -3 scripts/full_stack_launch_test.py --http-only --soft-ready`
|
||||||
أو:
|
أو من جذر `salesflow-saas`:
|
||||||
`.\scripts\grand_launch_verify.ps1 -HttpCheck -SoftReady`
|
`.\scripts\grand_launch_verify.ps1 -HttpCheck -SoftReady`
|
||||||
مع `DEALIX_BASE_URL` إذا لم يكن الـ API على `http://127.0.0.1:8000`.
|
مع `DEALIX_BASE_URL` إذا لم يكن الـ API على `http://127.0.0.1:8000`.
|
||||||
|
|
||||||
|
|||||||
1
salesflow-saas/frontend/next-env.d.ts
vendored
1
salesflow-saas/frontend/next-env.d.ts
vendored
@ -1,5 +1,6 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
|
/// <reference path="./.next/types/routes.d.ts" />
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
|
|||||||
@ -16,7 +16,7 @@ export default defineConfig({
|
|||||||
webServer: {
|
webServer: {
|
||||||
command: "node .next/standalone/server.js",
|
command: "node .next/standalone/server.js",
|
||||||
url: "http://127.0.0.1:3000",
|
url: "http://127.0.0.1:3000",
|
||||||
timeout: 120_000,
|
timeout: 180_000,
|
||||||
reuseExistingServer: !process.env.CI,
|
reuseExistingServer: !process.env.CI,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
7
salesflow-saas/scripts/kill-port-3000.ps1
Normal file
7
salesflow-saas/scripts/kill-port-3000.ps1
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Stops processes listening on TCP port 3000 (fixes Playwright webServer "port already in use").
|
||||||
|
# Run from salesflow-saas: .\scripts\kill-port-3000.ps1
|
||||||
|
$ErrorActionPreference = "SilentlyContinue"
|
||||||
|
Get-NetTCPConnection -LocalPort 3000 -ErrorAction SilentlyContinue | ForEach-Object {
|
||||||
|
Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
Write-Host "Port 3000 cleared (if anything was listening)." -ForegroundColor DarkGray
|
||||||
@ -1,10 +1,14 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Scan frontend/src for literal /api/v1/... path strings and verify exact matches
|
Scan frontend/src for /api/v1/... path strings and verify exact matches
|
||||||
against the FastAPI OpenAPI schema.
|
against the FastAPI OpenAPI schema.
|
||||||
|
|
||||||
|
Detects:
|
||||||
|
- Quoted literals: '/api/v1/foo', "/api/v1/foo", `/api/v1/foo`
|
||||||
|
- Template tails after ${...}: `${base}/api/v1/foo` (query string stripped)
|
||||||
|
|
||||||
Run from anywhere:
|
Run from anywhere:
|
||||||
py salesflow-saas/scripts/verify_frontend_openapi_paths.py
|
py -3 salesflow-saas/scripts/verify_frontend_openapi_paths.py
|
||||||
|
|
||||||
Requires backend deps on PYTHONPATH (run after: cd salesflow-saas/backend && py -m pip install -r requirements.txt).
|
Requires backend deps on PYTHONPATH (run after: cd salesflow-saas/backend && py -m pip install -r requirements.txt).
|
||||||
"""
|
"""
|
||||||
@ -15,6 +19,10 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Paths that appear in the frontend but use OpenAPI path parameters ({id}, etc.)
|
||||||
|
# or are intentionally not registered as separate operations — extend only with a comment.
|
||||||
|
OPENAPI_PATH_ALLOWLIST: frozenset[str] = frozenset()
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
saas = Path(__file__).resolve().parent.parent
|
saas = Path(__file__).resolve().parent.parent
|
||||||
@ -31,30 +39,37 @@ def main() -> int:
|
|||||||
schema = app.openapi()
|
schema = app.openapi()
|
||||||
open_paths = {p.rstrip("/") or "/" for p in schema.get("paths", {}).keys()}
|
open_paths = {p.rstrip("/") or "/" for p in schema.get("paths", {}).keys()}
|
||||||
|
|
||||||
# Literal path segments in quotes or template strings (no ${...} inside path)
|
quoted = re.compile(r"""['"`]((/api/v1/[a-zA-Z0-9_\-./]+))['"`]""")
|
||||||
pat = re.compile(r"""['"`]((/api/v1/[a-zA-Z0-9_\-./]+))['"`]""")
|
after_subst = re.compile(r"\$\{[^}]+\}(/api/v1/[a-zA-Z0-9_\-./]+)")
|
||||||
|
|
||||||
found: set[str] = set()
|
found: set[str] = set()
|
||||||
for p in fe_src.rglob("*"):
|
for p in fe_src.rglob("*"):
|
||||||
if p.suffix not in (".ts", ".tsx"):
|
if p.suffix not in (".ts", ".tsx"):
|
||||||
continue
|
continue
|
||||||
text = p.read_text(encoding="utf-8", errors="ignore")
|
text = p.read_text(encoding="utf-8", errors="ignore")
|
||||||
for m in pat.finditer(text):
|
for pat in (quoted,):
|
||||||
raw = m.group(1).rstrip("/")
|
for m in pat.finditer(text):
|
||||||
if "${" in raw or "{" in raw:
|
raw = m.group(1).split("?")[0].rstrip("/")
|
||||||
continue
|
if "${" in raw or "{" in raw:
|
||||||
|
continue
|
||||||
|
if raw.endswith("/api/v1"):
|
||||||
|
continue
|
||||||
|
found.add(raw)
|
||||||
|
for m in after_subst.finditer(text):
|
||||||
|
raw = m.group(1).split("?")[0].rstrip("/")
|
||||||
if raw.endswith("/api/v1"):
|
if raw.endswith("/api/v1"):
|
||||||
continue
|
continue
|
||||||
found.add(raw)
|
found.add(raw)
|
||||||
|
|
||||||
missing = sorted(p for p in found if p not in open_paths)
|
missing = sorted(p for p in found if p not in open_paths and p not in OPENAPI_PATH_ALLOWLIST)
|
||||||
if missing:
|
if missing:
|
||||||
print("Frontend literal paths not found as exact OpenAPI paths (may use path params or be dynamic):")
|
print("Frontend paths not found as exact OpenAPI paths (may use path params or be dynamic):")
|
||||||
for m in missing:
|
for m in missing:
|
||||||
print(f" - {m}")
|
print(f" - {m}")
|
||||||
print("\nTip: paths with {{id}} in OpenAPI need manual review.")
|
print("\nTip: paths with {id} in OpenAPI need allowlisting or a manual mapping.")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
print(f"OK: {len(found)} literal /api/v1 paths match OpenAPI.")
|
print(f"OK: {len(found)} /api/v1 paths in frontend match OpenAPI.")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user