Two changes that make 'docker compose up' actually work on this host
(and on any corporate network with TLS interception of npmjs.org):
1. backend/Dockerfile gains the same NODE_TLS_REJECT_UNAUTHORIZED=0 +
NPM_CONFIG_STRICT_SSL=false envs and 'npm config set strict-ssl false'
step that web/Dockerfile already had. Without this, the 'npm install
-g pnpm@10.6.5' step failed with UNABLE_TO_GET_ISSUER_CERT_LOCALLY
on corp networks. Build-time-only; production runtime image is
unaffected.
2. docker-compose.override.yml (new) is picked up automatically by
'docker compose up' and:
- remaps the web container's host port from 3000 to 3050 (port 3000
on this host is held by Grafana). Uses 'ports: !override' so the
base port mapping is replaced rather than appended.
- points the backend at the sibling platform-service (4003),
extraction-service (4005), and mcp-server (4007) running on the
host network via host.docker.internal.
- sets DB_PROVIDER=memory and a 32+ char JWT_SECRET so the backend
starts in dev mode without Cosmos credentials.
Verified live on this host:
docker compose up -d → both notelett-backend (healthy) and
notelett-web running.
curl http://localhost:4016/health → {status:ok,service:notelett-backend}
curl http://localhost:3050/dashboard → HTTP 200, '<title>NoteLett</title>'
The existing 380-test backend suite runs entirely against the in-memory
datastore provider, which treats every partition-key value as equivalent.
This hid one entire class of bug — partition-key mismatches — until
production. D7 closes that gap.
Implementation:
- backend/src/test-helpers.ts adds useCosmosDatastore() that swaps the
active provider for CosmosDatastoreProvider using COSMOS_ENDPOINT /
COSMOS_KEY / COSMOS_DATABASE. Throws synchronously when env is missing
so a misconfigured run fails loudly instead of silently falling back
to in-memory.
- backend/vitest.config.ts now excludes src/**/*.cosmos.test.ts so the
default 'pnpm test' run stays green for contributors without Docker.
- backend/vitest.cosmos.config.ts (new) includes ONLY *.cosmos.test.ts,
bumps testTimeout to 30s / hookTimeout to 60s for the real client
round-trips, and locks DB_PROVIDER=cosmos in test env.
- backend/src/cosmos.smoke.cosmos.test.ts (new) covers the four most
important partition-key contracts in NoteLett:
workspaces /userId
notes /workspaceId
note_tasks /workspaceId
note_shares /workspaceId (full create → resolve → delete → null)
Each test also asserts that a wrong-partition-key lookup returns null,
which is the failure mode the in-memory provider cannot simulate.
- backend/package.json adds 'test:cosmos' script.
- .github/workflows/ci.yml gains a backend-cosmos job that boots the
official mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator
container as a service, waits for it to be ready (60 × 5s polls of
/_explorer/emulator.pem), then runs pnpm test:cosmos against it.
The job depends on the existing backend job so the emulator only
spins up after unit tests pass.
Verified locally:
- pnpm --filter @notelett/backend test: 380/380 (cosmos suite excluded)
- vitest list --config vitest.cosmos.config.ts: 4 tests under the cosmos
smoke suite, as designed
- pnpm run verify: end-to-end green (backend 380/380, web 96/96,
mobile 97/97)
- ci.yml passes Python yaml.safe_load
CI verification: the new job will execute on the next push. Local
verification against the emulator requires Docker on the dev host.
Sprint B — closes audit items B6 (event-bus completeness) and B3
(public-share revocation regression).
Event bus:
- note-tasks/repository.ts createNoteTask now emits task.created with
taskId, noteId, workspaceId, userId, title
- workspaces/repository.ts createWorkspace now emits workspace.created
with workspaceId, userId, name
The event-bus already declared these event types (event-bus.ts) and
webhook subscribers can target them, but they were never emitted —
making the contract dead. Emissions follow the same .catch(() => {})
pattern used by note.created/updated/deleted in notes/repository.ts so
a subscriber failure cannot break the create flow.
Regression tests:
- note-tasks/repository.test.ts and workspaces/repository.test.ts
exercise the emission paths end-to-end through the in-memory
datastore.
- note-shares/repository.integration.test.ts adds a 5-test integration
suite for the public-share revocation path: token resolves before
revocation; token returns null after deleteShare (hard delete);
expired token returns null; cross-product token rejected;
listSharesForNote does not include revoked shares.
Verified:
- pnpm --filter @notelett/backend run test: 380/380 (was 373, +7 new)
- pnpm run verify end-to-end green
- Fixed NEXT_PUBLIC_NOTES_API_URL to use public API endpoint
- Updated docker-compose.yml environment format to proper YAML
- Updated Dockerfiles to remove Gitea secrets and use .docker-deps
- Added docker-prep.sh script for dependency packaging
- Changed NODE_ENV back to development for compatibility with memory DB
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The base image approach is too complex for the current pnpm workspace structure.
Products cannot easily use the base image's workspace because pnpm expects all
workspace packages to be present during install. Reverting to the proven
docker-prep.sh tarball approach for now.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The base image only includes production dependencies, so we need to install
all dependencies (including devDependencies) in the builder stage to have
TypeScript and Next.js available for building.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Update Dockerfiles to use bytelyst-common-base-backend and bytelyst-common-base-web
images instead of installing @bytelyst/* packages via tarballs.
Benefits:
- Smaller final images (~50MB vs ~250MB)
- Faster builds (base image cached)
- Consistent package versions across products
- No need for docker-prep.sh tarball packing
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Remove duplicate cosine similarity implementation in favor of the
shared @bytelyst/palace primitive. All consumers import from
embeddings.ts unchanged.
Enrich the system prompt with L0/L1/L2 workspace context from the
palace when running Smart Actions. Best-effort — failures never block
prompt execution. Gives LLM access to decisions, preferences, and
semantically relevant memories from the workspace.
After storing memories, generate subject-predicate-object triples from
entity pairs found in extracted memories. Also trigger L1 critical facts
cache regeneration so wake-up context stays fresh.
Promise.allSettled only catches rejected promises, not synchronous throws.
Wrap handler calls in Promise.resolve().then() to isolate sync errors.
Add 6 unit tests covering delivery, unsubscribe, error isolation,
singleton, reset, and removeAll.
- New lib/webhook-subscriber.ts: bridges event bus to webhook dispatch.
Registers listeners on all 5 domain events (note.created, updated,
deleted, task.created, workspace.created). Dispatches to registered
targets with HMAC-SHA256 signing, retry, and delivery log.
- server.ts: init webhook subscriber on startup, stop on close.
- Adds @bytelyst/webhook-dispatch dependency.
Alpine breaks under corporate proxy TLS interception. Debian slim
works reliably. NODE_TLS_REJECT_UNAUTHORIZED=0 removed from production
stages — only kept in build stages where npm registries need it.
Both packages are published to Gitea (llm@0.1.5, palace@0.1.4).
File refs broke Docker builds and caused 8 test files to fail due to
stale dist/providers/fallback.js.
Also removes unused @bytelyst/events dependency (not on Gitea registry).
All @bytelyst/* packages are internal to the ByteLyst ecosystem and
published to the private Gitea registry. Using "*" eliminates version
bump noise — always resolves to latest available.