Root cause: docker-compose.yml hardcoded NEXT_PUBLIC_NOTES_API_URL to https://api.bytelyst.com/notelett — a production URL that doesn't exist on this network — as the *build arg* for the web image. The docker-compose.override.yml correctly set localhost:4016/api but only on the runtime environment, which has no effect because NEXT_PUBLIC_* values are baked into the Next.js bundle at build time (pnpm run build inside the Dockerfile), not read at runtime. Symptom: every authenticated client-side fetch from the deployed web container went to https://api.bytelyst.com/notelett/... which the corporate proxy intercepted with a blockpage. The saved-views client in particular fired on every (app)/ layout mount, surfacing a 'Failed to fetch' toast on dashboard load. 4 release-flows.spec tests failed because page.route('**/api/**') couldn't match the api.bytelyst.com URLs at all. Discovery: inspected the deployed bundle inside the running container. 'grep -oE "api.bytelyst.com" /app/web/web/.next/static/chunks/*.js' returned multiple hits across the (app)/ layout, (auth)/ pages, and share page. The string was absent from the source tree, which proved it had been injected at build time via the broken arg default. Discovery debug pattern (kept for future use): page.on('requestfailed', r => console.log(r.method(), r.url())); page.route('**/api/**', route => route.fulfill({status:200,body:'{}'})); await page.goto('/dashboard'); // FAILED REQUESTS will list any URL not under /api/** that the SPA // attempted, exposing baked-in production URLs immediately. Fix (three layers, defense in depth): 1. docker-compose.yml — replace hardcoded 'NEXT_PUBLIC_NOTES_API_URL: https://api.bytelyst.com/notelett' in the build.args block with '${NEXT_PUBLIC_NOTES_API_URL:-http://localhost:4016/api}'. Same treatment for the runtime environment block. Add build args for the four other NEXT_PUBLIC_* values (extraction, MCP, diagnostics, product name/id, telemetry transport) so a single env var on the host controls both build and runtime layers. 2. web/Dockerfile — declare ARG and ENV lines for all seven NEXT_PUBLIC_* values so the build args reach 'pnpm run build'. Previously only NOTES_API_URL and PLATFORM_SERVICE_URL were declared, which meant overriding extraction/MCP/diagnostics via docker compose silently had no effect on the bundle. 3. docker-compose.override.yml — add a build.args block mirroring the four URL overrides so the local-only override also reaches build time, not just runtime. Comment block explains the bake-time vs runtime distinction so future contributors don't repeat the bug. Verified end-to-end after the fix: - docker compose build --no-cache web + up -d → grep of bundle now shows 'localhost:4016/api', api.bytelyst.com fully gone. - Debug interception test: zero requestfailed events on /dashboard. - Playwright release-flows.spec.ts: 4 failed → 4 passed (after URL fix; no test code changed for these four tests). - Full Playwright suite (--ignore-snapshots): 43 passed. - scripts/e2e-docker-test.sh: 9/9 backend API lifecycle steps pass. - pnpm run verify: backend 380/380, web 96/96, mobile 97/97. |
||
|---|---|---|
| .gitea/workflows | ||
| .github | ||
| .husky | ||
| backend | ||
| docs | ||
| mobile | ||
| scripts | ||
| shared | ||
| web | ||
| .aider.conf.yml | ||
| .clinerules | ||
| .cursorrules | ||
| .dockerignore | ||
| .editorconfig | ||
| .gitignore | ||
| .npmrc | ||
| .npmrc.docker | ||
| .nvmrc | ||
| .pnpmfile.cjs | ||
| .windsurfrules | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| docker-compose.override.yml | ||
| docker-compose.yml | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
NoteLett
Structured notes platform for humans and AI agents — part of the ByteLyst ecosystem.
Quick Start
Prerequisites:
- pnpm 10.6.5
- sibling common-platform checkout at
../learning_ai_common_plat(override withBYTELYST_COMMON_PLAT_ROOTif your layout differs) - optional local ByteLyst services from common platform:
platform-serviceon port 4003 for auth, flags, telemetry, diagnostics, billing, and blobextraction-serviceon port 4005 for URL/task extractionmcp-serveron port 4007 for agent tooling
# Install against the local common-platform workspace packages.
pnpm run install:common-plat --frozen-lockfile
# Registry fallback when explicitly needed.
source ~/.zshrc
pnpm run install:gitea --frozen-lockfile
# Backend in local memory mode (port 4016)
DB_PROVIDER=memory JWT_SECRET=dev-secret-do-not-use-in-prod \
pnpm --filter @notelett/backend run dev
# Web (port 3000)
pnpm --filter @notelett/web run dev
# Mobile
pnpm --filter @notelett/mobile run start
Auth is expected to come from platform-service. Local development can use the repo's dev/test helpers and memory datastore, but production must use real platform auth, Cosmos, and encryption configuration.
Docker path:
docker compose build
docker compose up -d
curl -sf http://localhost:4016/health
curl -sf http://localhost:4016/api/bootstrap
Local production-readiness smoke:
pnpm run smoke:local
# Use an already-running backend or skip shared service checks when isolating product behavior.
SMOKE_START_BACKEND=0 pnpm run smoke:local -- --no-start
pnpm run smoke:local -- --skip-platform
# Docker compose build/start/health smoke
pnpm run smoke:compose
Architecture
| Surface | Stack | Port |
|---|---|---|
| Backend | Fastify 5 + TypeScript ESM | 4016 |
| Web | Next.js 16 + React 19 | 3000 |
| Mobile | Expo + React Native | 8081 |
| Platform | platform-service (shared) | 4003 |
| Extraction | extraction-service (shared) | 4005 |
| MCP | mcp-server (shared) | 4007 |
Architecture Boundaries
NoteLett keeps product-local domain behavior in this repo: note/workspace CRUD, relationships, tasks, artifacts, agent action audit trails, saved views, prompt templates/runners, intake rules/jobs, note sharing/collaboration, version history, Palace memory/KG UX, and all NoteLett-specific web/mobile workflows.
Common-platform responsibilities come from ../learning_ai/learning_ai_common_plat: auth/session primitives, API clients, datastore/Cosmos abstractions, shared error/config/logging conventions, telemetry, diagnostics, feature flags, kill switch, blob access, extraction-service clients, design tokens, shared UI primitives where appropriate, MCP server integration, webhook dispatch, encryption helpers, and cross-repo automation scripts.
Package resolution defaults to local common-platform packages through .pnpmfile.cjs (BYTELYST_PACKAGE_SOURCE=common-plat). Use pnpm run install:common-plat for local development and pnpm run install:gitea only when you intentionally want registry versions. Override the local checkout with BYTELYST_COMMON_PLAT_ROOT=/path/to/learning_ai_common_plat.
Do not move NoteLett-specific notes logic into common platform unless another product has a concrete reuse need. Do not create repo-local substitutes for platform concerns already covered by @bytelyst/* packages or platform services.
Key Features
- Backend modules: notes, workspaces, relationships, tasks, artifacts, agent actions, saved views, Smart Actions, intake, collaborators, shares, versions, Palace, and ecosystem import routes
- 8 MCP tools: list, get, search, create_draft, update, link_notes, extract_tasks, attach_artifact
- Smart Actions: 20 built-in prompt templates, copilot text transforms, scheduler, webhooks, URL extraction
- Intake and Palace: URL/text intake jobs, intake rules, MemPalace memory/search/KG/wake-up routes
- Agent audit trail: every write tool records agent action history
- Datastore abstraction: Cosmos DB in production, in-memory for tests
- Platform integrations: auth (JWT), telemetry, diagnostics, feature flags, kill-switch, blob storage
- LLM integration:
@bytelyst/llmwith retry, timeout, and fallback heuristics
Environment
Copy backend/.env.example to backend/.env and web/.env.example to web/.env.local as needed.
Local memory mode:
NODE_ENV=developmentDB_PROVIDER=memoryJWT_SECRET=dev-secret-do-not-use-in-prodLLM_PROVIDER=mock- shared service URLs can point at local common-platform ports or remain disabled for isolated backend tests
Production requirements:
NODE_ENV=production- strong
JWT_SECRETshared with platform-service or the production auth verification mechanism DB_PROVIDER=cosmosCOSMOS_ENDPOINT,COSMOS_KEY, andCOSMOS_DATABASEFIELD_ENCRYPT_ENABLED=truewithFIELD_ENCRYPT_KEY_PROVIDER=akvor a managed key provider and required key materialPLATFORM_SERVICE_URL,EXTRACTION_SERVICE_URL, andMCP_SERVER_URLNEXT_PUBLIC_MCP_SERVER_URL=http://localhost:4007/apifor local web settings/agent guidanceTELEMETRY_ENABLED=trueandFEATURE_FLAGS_ENABLED=truewhen platform services are availableLLM_PROVIDERplus provider credentials (OPENAI_API_KEYor Azure OpenAI settings) for non-mock AI behavior
The May 5 production-readiness pass hardened production config to fail closed on unsafe defaults; see docs/PRODUCTION_READINESS_HANDOFF_ROADMAP.md.
Tests
pnpm --filter @notelett/backend run typecheck
pnpm --filter @notelett/backend run test
pnpm --filter @notelett/backend run lint
pnpm --filter @notelett/web run typecheck
pnpm --filter @notelett/web run test
pnpm --filter @notelett/web run lint
pnpm --filter @notelett/web run test:e2e
pnpm --filter @notelett/mobile run typecheck
pnpm --filter @notelett/mobile run test
pnpm --filter @notelett/mobile run lint
pnpm run verify
Current May 5 production-readiness status:
pnpm run verifypasses backend/web/mobile typecheck and tests, plus backend/web production builds.- backend, web, and mobile lint commands exit 0 with tracked advisory warnings.
- web Playwright release flows pass.
- release-guard audits pass common-platform secret scan, hardcoded color/token checks, and active product/API drift checks.
- Docker compose smoke and live shared-service smoke are explicit environment deferrals on this host because Docker is unavailable and platform-service/extraction-service/mcp-server are not running with Cosmos credentials.
See docs/PRODUCTION_READINESS_HANDOFF_ROADMAP.md Phase P10 for exact commands, commit hashes, warnings, and deferral notes.
Docs
AGENTS.md— AI agent onboarding guidedocs/PRD.md— Product requirementsdocs/ROADMAP.md— Master execution trackerdocs/PRODUCTION_READINESS_HANDOFF_ROADMAP.md— Active production-readiness checklistdocs/PLATFORM_SMOKE_CHECKS.md— Shared platform and NoteLett smoke commandsdocs/MOBILE_PRODUCTION_BUILD_AND_SMOKE.md— Expo build notes and iOS/Android smoke checklistdocs/RELEASE_CHECKLIST.md— Release notes template, deploy checklist, rollback, migrations, and monitoring placeholdersdocs/COSMOS_DATA_OPERATIONS.md— Cosmos containers, indexes, retention, and backup/restore approachdocs/SEED_BOOTSTRAP_STRATEGY.md— Built-in prompt, intake rule, onboarding workspace, and feature-flag bootstrap strategydocs/DATA_MIGRATION_AND_BACKFILL_PLAN.md— Encrypted-field, schema-change, and backfill migration plandocs/TELEMETRY_AND_DIAGNOSTICS_TAXONOMY.md— Event taxonomy and diagnostic breadcrumb contractdocs/OPERATOR_RUNBOOK.md— Incident triage and recovery steps for dependencies, scheduler/webhooks, blob, LLM/extraction, reviews, and MCPdocs/UI_UX_PLATFORM_CORE_ROADMAP.md— UI/UX migration plan for moving reusable components into common-platform core UI while keeping a thin NoteLett adapter