# ConusAI Showcase Notes with attachments on Postgres and Blob Storage, audited, observed and metered: every ConusAI SDK in one Next.js app built with Feature-Sliced Design (showcase plan D11). The template is proven in this repository by `scripts/vendor/test-template.sh` at the same commit as the SDKs it uses (D18). ## Pinned versions Pinned on 2026-10-06 with `npm view version` (showcase ยง2.7): | Package | Version | |---|---| | next | 16.3.8 | | react, react-dom | 19.3.0 | | typescript | 5.9.3 (5.x: the `@conusai-sdk/plugin` peer requires ^5) | | drizzle-orm, drizzle-kit | 0.45.3, 0.31.11 | | postgres | 3.4.9 | | zod | 4.6.5 | | server-only | 0.0.1 | | vitest | 5.0.3 | | eslint, eslint-config-next, @eslint/eslintrc | 9.39.5 (ESLint 10 breaks the React plugin bundled by eslint-config-next), 16.3.8, 3.3.7 | | steiger, @feature-sliced/steiger-plugin | 0.7.0, 0.8.0 | | @playwright/test | 1.63.0 | | playwright-core | 1.63.0 (`@axe-core/playwright`'s peer; must equal `@playwright/test`'s copy, or a lockfile-less `npm install` hoists the newest and the two `Page` types diverge under `tsc`) | | @types/node, @types/react, @types/react-dom | 26.6.4, 19.3.0, 19.3.0 | The `@conusai-sdk/*` packages the template imports are pinned in `package.json` at the version the SDK source tree carries at the same commit; `test/sdk-deps.test.ts` fails when an imported package is missing or its pin differs. The template ships **no `package-lock.json`** (decision of 2026-10-09, showcase plan D19): a lockfile without the scoped entries makes `npm ci` fail, and one carrying them records `resolved` URLs of one install's registry host, which is wrong on every other. The platform build runs `npm install` against the `.npmrc` the deployer mounts as a BuildKit secret (D6/D7), whose scoped registry serves exactly the pinned versions; `test-template.sh` proves the same locally from the bundle's tarballs. ## Layout - `app/` routes only; each file re-exports from `src/views`, `src/app` or a feature's route handler. - `src/app`, `src/views`, `src/widgets`, `src/features`, `src/entities`, `src/shared`: the FSD layers, imports point downward only (checked by `steiger`). - `src/shared/config/env.ts`: the environment, parsed once with zod (D12). - `src/shared/api/*/server.ts`: server-only SDK clients (`server-only`). - `src/shared/lib/visitor.ts`: the signed `sc_vid` visitor cookie (D16). ## What each slice demonstrates | Slice | Demonstrates | |---|---| | `features/create-note` | A note in Postgres, audited as `note.created`; NATS announces it and Qdrant indexes it when those are linked. | | `features/edit-note`, `features/delete-note` | Writes scoped to the author, each audited (`note.updated`, `note.deleted`). | | `features/upload-file`, `features/delete-file` | Attachments in Blob Storage, one usage event per upload with an idempotency key; a per-minute quota when KV is linked. | | `features/download-file` | An attachment's bytes at `/files/`, downloaded server-side through the Blob API and streamed to the visitor who attached it: the platform's blob URL needs the deployment token, so the browser cannot open it. | | `features/publish-note-event` | An author re-announces a note on NATS (`note.announced` in the audit log); another visitor is refused. | | `features/search-notes` | Similar-note search in Qdrant, when Qdrant is linked. | | `features/export-notes` | The visitor's notes written as one JSON object to the dedicated S3 bucket, when S3 is linked. | | `features/rate-limit` | The uploads left this minute, read from KV, when KV is linked. | | `features/simulate-traffic` | A scripted visitor journey that produces observed page views, a started journey and an error. | | `widgets/note-list`, `widgets/attachments` | The visitor's notes and their attachments, with the controls each feature provides. | | `widgets/audit-timeline`, `widgets/usage-meter` | The platform's audit events for this project, and the visitor's metered uploads and bytes. | | `widgets/enable-card`, `widgets/module-panel` | One slot per optional module: its feature when linked, its enable card (text from the platform's catalog) when not (D13). | | `views/dashboard`, `views/audit`, `views/platform` | The composed pages; the platform page lists each optional service as linked or not. | ## Optional modules The showcase reads the variables the platform injects for each linked service (D8, D13). A module without its variables shows its enable card instead of its feature. Its variables are `REDIS_URL` (KV), `NATS_URL` and `NATS_TOKEN`, `QDRANT_URL` and `QDRANT_API_KEY`, `GIT_URL`, and `AWS_ENDPOINT_URL`, `S3_BUCKET`, `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`. The S3 names are the ones the platform injects for an S3 service. ## Commands - `npm run typecheck`, `npm run steiger`, `npm run lint`, `npm test`, `npm run build` - `npm run e2e` runs the Playwright suite against a production build. It starts `e2e/fake-platform.mjs` in place of the platform and withholds the optional module variables, so every enable card shows. The suite covers creating a note and its audit entry, an attachment moving the usage meter, the enable cards, axe (no serious or critical issues on each page) and the Core Web Vitals budgets (LCP at most 2.5 s, INP at most 200 ms) measured in Chromium. - `npm test` also runs `src/shared/lib/optional.live.test.ts` against live NATS, Qdrant and S3 when `NATS_URL`, `QDRANT_URL` and `AWS_ENDPOINT_URL` are set; without them it is skipped. - `bash scripts/vendor/test-template.sh` from the repository root runs all of them against the bundle; `bash scripts/vendor/test-template.sh --e2e` adds the Playwright suite.