diff --git a/README.md b/README.md index f40914f..64c7825 100644 --- a/README.md +++ b/README.md @@ -119,3 +119,4 @@ Current baseline note: after common-platform workspace alignment, `pnpm install - [`docs/PRD.md`](docs/PRD.md) — Product requirements - [`docs/ROADMAP.md`](docs/ROADMAP.md) — Master execution tracker - [`docs/PRODUCTION_READINESS_HANDOFF_ROADMAP.md`](docs/PRODUCTION_READINESS_HANDOFF_ROADMAP.md) — Active production-readiness checklist +- [`docs/PLATFORM_SMOKE_CHECKS.md`](docs/PLATFORM_SMOKE_CHECKS.md) — Shared platform and NoteLett smoke commands diff --git a/docs/PLATFORM_SMOKE_CHECKS.md b/docs/PLATFORM_SMOKE_CHECKS.md new file mode 100644 index 0000000..bd06bb1 --- /dev/null +++ b/docs/PLATFORM_SMOKE_CHECKS.md @@ -0,0 +1,212 @@ +# NoteLett Platform Smoke Checks + +Status: active production-readiness smoke reference +Last updated: May 5, 2026 + +Use these checks to prove NoteLett is running against the shared ByteLyst platform services, not only compiling against `@bytelyst/*` packages. The common-platform source of truth is `../learning_ai/learning_ai_common_plat`; prefer its compose files and scripts when bringing up shared services. + +## 1. Bring Up Shared Services + +From `../learning_ai/learning_ai_common_plat`: + +```bash +docker compose up -d platform-service extraction-service mcp-server +docker compose ps platform-service extraction-service mcp-server +``` + +Expected local ports: + +| Service | Port | Purpose | +| --- | ---: | --- | +| `platform-service` | 4003 | Auth, telemetry, diagnostics, flags, kill switch, blob, billing | +| `extraction-service` | 4005 | Extraction, task extraction, URL/content processing, transcription | +| `mcp-server` | 4007 | Shared MCP tool registry and tool execution | +| `notelett-backend` | 4016 | Product backend | +| `notelett-web` | 3000 | Product web app | + +## 2. Environment + +Use these defaults for local smoke runs: + +```bash +export PLATFORM_URL="${PLATFORM_URL:-http://localhost:4003}" +export PLATFORM_API_URL="${PLATFORM_API_URL:-http://localhost:4003/api}" +export EXTRACTION_URL="${EXTRACTION_URL:-http://localhost:4005}" +export MCP_ORIGIN="${MCP_ORIGIN:-http://localhost:4007}" +export MCP_URL="${MCP_URL:-http://localhost:4007/api}" +export NOTELETT_URL="${NOTELETT_URL:-http://localhost:4016}" +export NOTELETT_API_URL="${NOTELETT_API_URL:-http://localhost:4016/api}" +export PRODUCT_ID=notelett +``` + +Authenticated platform, blob, and MCP calls require a platform bearer token: + +```bash +export TOKEN="" +``` + +When using common-platform compose locally, generate test tokens with the same mechanism used by `../learning_ai/learning_ai_common_plat/scripts/prototype-self-test.sh`: execute inside `platform-service` and call the built `createAccessToken()` helper with `productId: "notelett"`. + +## 3. Unauthenticated Health + +These should pass before authenticated smoke checks: + +```bash +curl -sf "$PLATFORM_URL/health" +curl -sf "$EXTRACTION_URL/health" +curl -sf "$MCP_ORIGIN/health" +curl -sf "$NOTELETT_URL/health" +curl -sf "$NOTELETT_API_URL/bootstrap" +``` + +Expected: + +- all health endpoints return 2xx +- `GET /api/bootstrap` returns `productId: "notelett"` and backend port `4016` +- if extraction sidecar is not enabled, service health can still pass while sidecar-specific checks below report degraded/unavailable + +## 4. Platform-Service Checks + +Telemetry: + +```bash +curl -sf "$PLATFORM_API_URL/telemetry/config?productId=$PRODUCT_ID" \ + -H "Authorization: Bearer $TOKEN" + +curl -sf "$PLATFORM_API_URL/telemetry/events" \ + -H "Authorization: Bearer $TOKEN" \ + -H "content-type: application/json" \ + -d '{"productId":"notelett","eventName":"notelett.smoke","timestamp":"2026-05-05T00:00:00.000Z","properties":{"source":"platform-smoke"}}' +``` + +Diagnostics: + +```bash +curl -sf "$PLATFORM_API_URL/diagnostics/config?productId=$PRODUCT_ID" \ + -H "Authorization: Bearer $TOKEN" + +curl -sf "$PLATFORM_API_URL/diagnostics/sessions?productId=$PRODUCT_ID&limit=1" \ + -H "Authorization: Bearer $TOKEN" +``` + +Feature flags and kill switch: + +```bash +curl -sf "$PLATFORM_API_URL/flags?productId=$PRODUCT_ID" \ + -H "Authorization: Bearer $TOKEN" + +curl -sf "$PLATFORM_API_URL/flags/evaluate" \ + -H "Authorization: Bearer $TOKEN" \ + -H "content-type: application/json" \ + -d '{"productId":"notelett","flagKey":"notelett.enabled","context":{"userId":"smoke-user"}}' +``` + +Blob: + +```bash +curl -sf "$PLATFORM_API_URL/blob/containers" \ + -H "Authorization: Bearer $TOKEN" + +curl -sf "$PLATFORM_API_URL/blob/sas" \ + -H "Authorization: Bearer $TOKEN" \ + -H "content-type: application/json" \ + -d '{"container":"attachments","blobName":"notelett/smoke/hello.txt","permissions":"rw","expiresInMinutes":10}' +``` + +For an end-to-end local blob upload/delete cycle, prefer the common-platform pattern in `scripts/prototype-self-test.sh` and substitute `productId: "notelett"` plus a `notelett/smoke/` blob prefix. + +## 5. Extraction-Service Checks + +```bash +curl -sf "$EXTRACTION_URL/api/extract/models" +curl -sf "$EXTRACTION_URL/api/extract/sidecar-health" +curl -sf "$EXTRACTION_URL/api/extract/cache-stats" +``` + +For a minimal extraction task: + +```bash +curl -sf "$EXTRACTION_URL/api/extract" \ + -H "content-type: application/json" \ + -d '{"productId":"notelett","taskType":"task_extraction","text":"Ship the production smoke checks and update the roadmap.","options":{"maxTasks":5}}' +``` + +Expected: + +- models/cache endpoints return 2xx +- sidecar health may be `degraded` in local dev if the Python sidecar is intentionally disabled; record that explicitly rather than treating it as an unknown +- extraction responses should include structured output or a stable error body + +## 6. MCP-Server Checks + +```bash +curl -sf "$MCP_URL/tools" \ + -H "Authorization: Bearer $TOKEN" +``` + +Confirm NoteLett tools are present in the returned registry, especially: + +- `notes.notes.list` +- `notes.notes.get` +- `notes.notes.search` +- `notes.notes.create_draft` +- `notes.notes.update` +- `notes.relationships.link` +- `notes.tasks.extract` +- `notes.artifacts.attach` + +Call a read-only tool: + +```bash +curl -sf "$MCP_URL/tools/call" \ + -H "Authorization: Bearer $TOKEN" \ + -H "content-type: application/json" \ + -d '{"name":"notes.notes.search","arguments":{"workspaceId":"","query":"smoke","limit":5}}' +``` + +Expected: + +- MCP server returns 2xx and wraps tool output in MCP `content` +- auth, role, product scope, request ID, and product backend errors are visible in logs +- write tools should be tested with dry-run/idempotency in P2.3/P3.5 before release + +## 7. NoteLett Backend Checks + +Start backend in memory mode for local product smoke: + +```bash +DB_PROVIDER=memory \ +JWT_SECRET="${JWT_SECRET:-dev-secret-do-not-use-in-prod}" \ +PLATFORM_SERVICE_URL="$PLATFORM_URL" \ +EXTRACTION_SERVICE_URL="$EXTRACTION_URL" \ +MCP_SERVER_URL="${MCP_URL%/api}" \ +pnpm --filter @notelett/backend run dev +``` + +Then check: + +```bash +curl -sf "$NOTELETT_URL/health" +curl -sf "$NOTELETT_API_URL/bootstrap" +curl -sf "$NOTELETT_API_URL/diagnostics/config" +curl -sf "$NOTELETT_API_URL/diagnostics/flags" +curl -sf "$NOTELETT_API_URL/diagnostics/telemetry" +``` + +Expected: + +- bootstrap identifies NoteLett +- diagnostics report `productId: "notelett"` and the configured shared service URLs +- production should not expose unauthenticated diagnostics without the P3.3 decision applied + +## 8. Recording Results + +For every smoke run, record: + +- date/time and git commit +- which services were running locally or remotely +- exact commands run +- pass/fail for health, bootstrap, telemetry, diagnostics, flags, kill switch, blob, extraction, MCP, and product backend +- any intentional local-dev degradation, such as extraction sidecar unavailable + +Production-readiness completion requires these checks to be automated or repeated through the final P10 gate. diff --git a/docs/PRODUCTION_READINESS_HANDOFF_ROADMAP.md b/docs/PRODUCTION_READINESS_HANDOFF_ROADMAP.md index 154acec..5e93c5c 100644 --- a/docs/PRODUCTION_READINESS_HANDOFF_ROADMAP.md +++ b/docs/PRODUCTION_READINESS_HANDOFF_ROADMAP.md @@ -122,7 +122,7 @@ Acceptance criteria: Goal: prove that NoteLett is using common platform services and packages at runtime, not just declaring dependencies. - [x] **P2.1** Align MCP URL defaults and examples across `web/src/lib/product-config.ts`, `web/.env.example`, settings copy, Docker env, and docs. Use common platform `mcp-server` port `4007` unless the shared server exposes a different production route. Commit: `da3129c`; Verified: legacy MCP port audit returned no matches outside git history, and `rg "NEXT_PUBLIC_MCP_SERVER_URL|MCP_SERVER_URL" web README.md docker-compose.yml docs/PRODUCTION_READINESS_HANDOFF_ROADMAP.md` shows web default/env/settings/Docker now use `http://localhost:4007/api`, matching common-platform `mcp-server` tool routes. -- [ ] **P2.2** Add or update platform smoke documentation for `platform-service`, `extraction-service`, `mcp-server`, telemetry, diagnostics, flags, kill switch, blob, and NoteLett backend health. Commit: +- [x] **P2.2** Add or update platform smoke documentation for `platform-service`, `extraction-service`, `mcp-server`, telemetry, diagnostics, flags, kill switch, blob, and NoteLett backend health. Commit: `pending`; Verified: `git diff --check`; added `docs/PLATFORM_SMOKE_CHECKS.md` covering common-platform startup, env, unauthenticated health, telemetry, diagnostics, flags/kill switch, blob SAS, extraction, MCP registry/call, NoteLett backend health/bootstrap/diagnostics, and result recording. - [ ] **P2.3** Add a local smoke script or extend existing scripts to check `GET /health`, `GET /api/bootstrap`, platform dependencies, and one authenticated product-backend flow in memory mode. Prefer reusing common platform smoke/self-test conventions. Commit: - [ ] **P2.4** Verify web and mobile shared clients propagate product identity, auth token, and request IDs where supported by common platform clients. Add tests where behavior is local. Commit: - [ ] **P2.5** Decide whether mobile should adopt `@bytelyst/react-native-platform-sdk` now or explicitly defer it. If adopted, replace redundant local composition; if deferred, document why direct clients are still preferred. Commit: