90 lines
5.6 KiB
Markdown
90 lines
5.6 KiB
Markdown
# 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 <package> 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/<id>`, 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.
|