smooth-app
A collaborative, free and open database of ingredients, nutrition facts and information on food products from around the world
For UK physiotherapy clinics: ClinForms completes each insurer's, medico-legal company's, solicitor's, case manager's or employer's own report form from your treatment notes, in its original layout, w
HealthTypeScript · JavaScriptGitHub @appstackxOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
For UK physiotherapy clinics: ClinForms completes each insurer's, medico-legal company's, solicitor's, case manager's or employer's own report form from your treatment notes, in its original layout, with every answer traceable to its source and approved by your clinician.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
ClinForms by AppStackX – complete every referrer's own report form from your clinic notes.
ClinForms completes each referrer's own report form – medico-legal company (MLC), insurer, solicitor, case
manager or employer – from a physiotherapy clinic's records, and has the treating physiotherapist
review and approve it before anything leaves the clinic.Read the full README ↗ClinForms by AppStackX – complete every referrer's own report form from your clinic notes.
| Product | ClinForms (vendor: AppStackX) |
| Repository | appstackx/clinforms (private) |
| Domain | clinforms.co.uk (www redirects to the apex) |
| Formerly | "AppStackX Reports" (renamed 09/10/2026; internal identifiers kept – see Renaming the product) |
ClinForms completes each referrer's own report form – medico-legal company (MLC), insurer, solicitor, case manager or employer – from a physiotherapy clinic's records, and has the treating physiotherapist review and approve it before anything leaves the clinic.
.docx or fillable PDF; a flat PDF on a best-effort basis) and the
patient's episode from the clinic system (registration details, treatment notes, appointments,
outcome measures) – through the clinic-system API, an uploaded export or a printed-notes PDF.Built-in report templates remain as the fallback when a referrer sends no form. The Report API
(/api/reports/v1) is the product; the Studio UI at /reports is the first app built on it.
Demo build – fictional data only. Reports and the forms library are stored in the browser. The clinic system is a Simulated TM3 sandbox (
/pms-sandbox,/api/tm3-sim/v1) with fictional patients, always labelled "Simulated TM3 sandbox – demo data, not affiliated with TM3".
The product name is set in exactly one place: PRODUCT in
src/modules/medreport/config.public.ts (see
Renaming the product).
| URL | What it is |
|---|---|
/ | Public website: the landing page for UK physiotherapy clinics (with /request-access, /security, /privacy, /cookies, /terms) |
/pms-sandbox | The simulated clinic system: patient list (Megan Hart and Daniel Brooks have full episodes) |
/pms-sandbox/patients/sim-pat-001 | A patient record (registration, notes, appointments, outcome measures, filed documents). Complete referrer's report form launches the Studio with this episode, through the Report API's partner launch |
/reports | Studio home: completed and in-progress forms, demo tools (import a case, reset) |
/reports/forms | Referrer forms library: bundled fictional forms with confirmed maps; Upload a referrer form reads a new form and proposes its map |
/reports/forms/[formId] | Check and confirm a form's map against the original layout |
/reports/new | Complete a form: pick the patient (simulated TM3, an uploaded export or a printed-notes PDF), the form, then draft |
/reports/[id] | Review question by question with sources, gaps and checks; preview the filled original; approve; download Word/PDF; save to the clinic record |
/reports/batch | Complete one form for several patients |
/reports/security | Security & data protection: roles, DPA/DPIA, data handling, approval, hosting, audit, retention |
/reports/templates | Built-in fallback templates (and validating a tagged Word template) |
/api/reports/v1/health | {product, version, aiMode, liveAiAvailable, …} |
A typical run: open /pms-sandbox → Megan Hart → Complete referrer's report form → pick
Harrow & Pike's form → the answers are drafted (demo mode replays prepared drafts, clearly badged) →
review, resolve the gaps, approve → download the completed form → Save to clinic record → the
sandbox's Documents tab shows the filed file. The full demo script and the planted gaps are in
docs/plan.md §9 and in the module README's "Demo data".
Customer-facing wording is neutral: screens, documents and exports describe what the product does and
never name the drafting technology or vendor (src/modules/medreport/core/wording.ts, guarded by
scripts/medreport/neutral-wording.test.ts).
src/app/ Next.js App Router – thin pages and route files only
layout.tsx root layout (metadata from PRODUCT, metadataBase, Inter via next/font,
cookie banner + consent-gated analytics)
(marketing)/** public website: landing page "/", /request-access, /security, /privacy,
/cookies, /terms (indexable)
(auth)/** sign-in pages: /login, /two-factor, /accept-invite, /reset-password (noindex,
no cookie banner) – docs/auth.md
app/** the signed-in clinic area (/app): overview + settings (clinic, members,
security, API keys); session, two-step and membership checked server-side
api/auth/[...all] the sign-in library's HTTP API
robots.ts sitemap.ts robots.txt (demo, app, APIs and sign-in pages disallowed) and sitemap.xml
not-found.tsx icon.svg
api/access-requests POST: the "Request access" form (validation, honeypot, rate limit, storage,
optional email notification – src/server/site/)
reports/** Studio pages (+ medreport-host.tsx: write-back into the sandbox record)
pms-sandbox/** simulated clinic system pages (+ actions.ts: server-to-server launch)
api/reports/v1/** Report API route files → module handlers
api/tm3-sim/v1/** simulated TM3 API route files → sandbox handlers
api/_medreport-glue.ts the one place that wires the module to the sandbox (connector registry)
src/modules/medreport/ THE PRODUCT (core, connectors, auth, ai, forms, docgen, templates, api, ui)
– see its README.md for the folder map, contracts and conventions
src/sandbox/tm3-sim/ the simulated TM3 clinic system (demo scaffolding, not the product)
src/components/ui/* generic UI primitives (button, card, dialog, …) – reached by the module
src/lib/utils.ts only through src/modules/medreport/ui/primitives.ts
src/components/marketing/ public-site header, footer, legal page layout, hero illustration
src/components/consent/ cookie banner + settings dialog; the `clinforms_consent` cookie (6 months)
src/components/account/ layout pieces for the sign-in pages and the clinic area
src/middleware.ts Edge: optimistic session-cookie redirect for /app only (real checks run in Node)
src/components/analytics/ consent-gated product analytics: allow-listed `track(event, props)`
src/lib/site.ts SITE_URL, COMPANY details (unknown ones stay unset and are not shown), public page list
src/server/ production data layer (db, crypto, repos – docs/database.md), auth/ and email/
(identity, clinics, invitations – docs/auth.md) and site/ (request access)
db/migrations/sqlite/ D1/SQLite migrations; supabase/migrations/ = the Postgres twins (parity-tested)
workers/data-gateway/ the authenticated SQL gateway Worker in front of D1 (own package.json)
scripts/db/ scripts/admin/ migrate, provision, self-test, copy-to-Postgres; create/list/offboard clinics
scripts/medreport/ tests, recorders, sample builders, ESLint boundary generator, video/
docs/plan.md the product plan and its revision history
Import boundaries are enforced by ESLint (.eslintrc.json, generated by
npm run medreport:eslint-boundary): the module never imports the sandbox, the app or the UI
primitives directly; the sandbox never imports the module; browser-safe folders never import
server-only code. Only src/app touches both sides.
Requires Node 22 (.nvmrc; Node 20.6+ works) and npm.
git clone [email protected]:appstackx/clinforms.git
cd clinforms
npm ci
cp .env.example .env.local # optional – leave everything empty for demo mode
npm run dev # http://localhost:3000 (landing page); the demo is at /reports
With no environment variables the app runs in demo mode: no AI calls, prepared drafts and form maps for the fictional data (clearly badged), and fixed public demo secrets. That is enough for the whole demo flow.
Production build:
npm run build
PORT=3000 MEDREPORT_AI_MODE=demo npm run start
Set PORT when you run next start: the server calls the simulated TM3 API on its own loopback port
(http://127.0.0.1:$PORT) and falls back to in-process calls when that is not possible.
Word → PDF copies of completed Word forms need LibreOffice (soffice) on the server. Without it
the app offers the Word file and /render?format=pdf answers 503 PDF_CONVERSION_UNAVAILABLE. On
macOS/Linux install LibreOffice, or point MEDREPORT_SOFFICE_PATH at the binary.
All are server-side except the two NEXT_PUBLIC_POSTHOG_* analytics settings (public by design: they
are inlined into the browser bundle at build time). The annotated list is .env.example;
copy it to .env.local (gitignored – never commit real values).
| Variable | Purpose |
|---|---|
ANTHROPIC_API_KEY | Live drafting and live form analysis. Without it the app runs in demo mode |
MEDREPORT_MODEL | Optional model override (allow-list in config.server.ts; default claude-sonnet-5-5) |
MEDREPORT_AI_MODE | auto (default), demo or live. Live needs the key and the passcode |
MEDREPORT_LIVE_PASSCODE | Presenter passcode that allows live calls (16+ random characters; rotate after demos) |
MEDREPORT_LAUNCH_SECRET | HMAC secret for launch and session tokens |
MEDREPORT_SIGNING_SECRET | HMAC secret for approval receipts, form-map confirmations and filed-document tokens |
MEDREPORT_ALLOW_DEMO_SECRETS | 1 lets a production deployment use the public demo secrets. Not recommended |
MEDREPORT_PARTNER_KEY | Partner key the clinic system sends on POST /api/reports/v1/launch |
TM3_SIM_TOKEN | Bearer token for the simulated TM3 API |
TM3_SIM_BASE_URL | Optional base URL of the simulated TM3 API (default: this server's own origin) |
MEDREPORT_SOFFICE_PATH | Optional path to LibreOffice for Word → PDF |
MEDREPORT_DEMO_ASSETS_DIR | Dev/demo only: folder of local demonstration forms (e.g. demo-assets/insurers, gitignored) with prepared maps and answers. Off in production |
MEDREPORT_DEMO_ASSETS_ALLOW_PROD | 1 lets a LOCAL production build (next start, as npm run demo:red runs) use that folder. Never on a deployment |
CLINFORMS_DB, CLINFORMS_*, DATABASE_* | Database and encryption at rest – see docs/database.md. Locally the default is a SQLite file (.data/clinforms.db); the "Request access" form stores requests there |
In demo mode, unset secrets fall back to fixed public demo constants – except the launch and signing
secrets on a Vercel production deployment (VERCEL_ENV=production), where they are derived from a
server-only secret or the request fails. Details: src/modules/medreport/README.md → "Environment
variables".
npx tsc --noEmit # or: npm run typecheck
npm run lint # includes the import-boundary rules
npm run test:medreport # node:test over src/modules/medreport, scripts/medreport and src/sandbox *.test.ts
npm run test:site # public site: consent cookie, analytics allow-lists, request access (SQLite), wording file scan
npm run test:db # data layer: migration parity, crypto, repositories on SQLite and PGlite (docs/database.md)
npm run test:auth # sign-in, invitations, two-step, roles, admin scripts (docs/auth.md)
npm run test:gateway # the D1 gateway Worker and the repositories through it (docs/database.md)
npm run build
test:medreport loads scripts/medreport/test-setup.mjs (maps server-only to an empty module) and
runs the TypeScript tests with tsx – 437 tests (RED wave 1 and 2 and their fixes, 09/10/2026; 3 skipped without LibreOffice), no network, no API key needed.
Other scripts (run with node --env-file=.env.local --import ./scripts/medreport/test-setup.mjs --import tsx <script>
unless noted):
| Script | Purpose |
|---|---|
npm run medreport:templates | Rebuild the built-in Word templates (templates/generated/*.docx.b64.ts) |
npm run medreport:forms | Rebuild the bundled fictional referrer forms; then re-record analyses and drafts |
npm run medreport:eslint-boundary | Regenerate the ESLint import boundary in .eslintrc.json |
scripts/medreport/record-form-analyses.ts | Record live analyses of the sample forms (needs the API key) |
scripts/medreport/record-demo-drafts.ts | Record the demo drafts (needs the API key) |
scripts/medreport/stamp-demo-drafts.ts | Re-stamp demo drafts after a fixture change (--dir=demo-assets/insurers for the local demonstration answers) |
npm run demo:check | Check the local demonstration forms, maps and answers (MEDREPORT_DEMO_ASSETS_DIR, else demo-assets/insurers). The default folder absent: one line, exit 0; a named folder absent, or forms with no prepared map: exit 1 |
npm run demo:red | The RED insurer-form demo on this machine: next build + next start on port 3000 with the demonstration assets, always in demo mode (-- --live lets .env.local's MEDREPORT_AI_MODE allow live calls; other .env.local values override the defaults). Refuses to start without the folder or without a prepared map (-- --allow-no-maps to start anyway) |
scripts/medreport/build-notes-pdf.ts, build-prewritten-drafts.ts, render-form-samples.ts | Sample builders |
scripts/medreport/video/record-demo.mjs | Records the walkthrough video against a running server (Playwright from NODE_PATH=$(npm root -g), ffmpeg); see its README |
appstackx/clinforms into Vercel (framework preset Next.js, default build
command, Node 22). Production branch: main.clinforms.co.uk as the production domain and www.clinforms.co.uk as a redirect to it,
in the project's Domains settings; then set the DNS records Vercel shows at the registrar.
https://clinforms.co.uk is the public website (landing page, legal pages, request access); the public
demo stays at /reports and /pms-sandbox.next.config.mjs sets HSTS, nosniff, Referrer-Policy, X-Frame-Options, Permissions-Policy,
COOP and a report-only Content Security Policy on every response, and X-Robots-Tag: noindex on the
APIs, the app, the demo and the sign-in pages. Switch the CSP to enforcing only after the Studio's review,
mapping and preview screens run clean (see the comment in next.config.mjs).NEXT_PUBLIC_POSTHOG_KEY (EU project) to enable the cookie banner and consent-gated
analytics. In the PostHog project settings, turn on "Discard client IP data" and set data retention to
match the privacy policy (12 months).vercel.json pins functions to London ("regions": ["lhr1"]), so patient data is
processed in the UK. Also choose a UK/EU region for anything else you attach.MEDREPORT_LAUNCH_SECRET, MEDREPORT_SIGNING_SECRET,
MEDREPORT_PARTNER_KEY and TM3_SIM_TOKEN; add ANTHROPIC_API_KEY (a spend-limited workspace) and
MEDREPORT_LIVE_PASSCODE only if live drafting should be available. Never set
MEDREPORT_ALLOW_DEMO_SECRETS in production.maxDuration = 60; all API routes run on the Node.js runtime.VERCEL_AUTOMATION_BYPASS_SECRET); otherwise it falls back to
in-process calls automatically.A Next.js App Router app can run on Cloudflare Workers with the OpenNext adapter
(@opennextjs/cloudflare, nodejs_compat). It has not been tried with this app, and these points
need work or acceptance first (limits as known at the time of writing – check the current ones):
child_process. Word → PDF degrades exactly as on Vercel (503, "download
Word"); a separate converter is still needed.src/modules/medreport/docgen/pdf/fonts.ts writes the DejaVu fonts
to os.tmpdir() and registers them by path; Workers have no persistent writable disk, so fonts
would have to be registered from memory.VERCEL_ENV=production; on Cloudflare set MEDREPORT_LAUNCH_SECRET and MEDREPORT_SIGNING_SECRET
explicitly (as Worker secrets).Recommendation: host the app on Vercel in lhr1 (or as a container – next start – on a UK
host, where LibreOffice can be installed alongside it). Cloudflare is a reasonable later option for the
API edge or static assets once the points above are addressed.
The product was renamed from "AppStackX Reports" to ClinForms on 09/10/2026. To rename it again,
change PRODUCT (name, shortName, tagline) in src/modules/medreport/config.public.ts; every
screen, page title and link preview, document property, download name, error message, the health
endpoint and the sandbox's "Connected apps" card read it from there. Then update this README,
package.json name, the repository name, and the literal PRODUCT_NAME / overlay text in
scripts/medreport/video/record-demo.mjs (the injected overlay cannot import the config).
Internal identifiers keep the earlier name on purpose, because changing them would break saved files, tokens and browser data:
appstackx-reports.import, appstackx-reports.case) and the recorded
data formats (appstackx-reports.demo-draft, appstackx-reports.form-analysis);appstackx-reports:<purpose>:v1) and the public demo secret constants in
config.server.ts;Bearer realm="appstackx-reports" value of the Report API's WWW-Authenticate header;appstackx-reports-fonts-v1 in the server's temp directory);medreport.), the module folder name and the API paths (/api/reports/v1).The bundled fictional referrer forms (build-demo-forms.mjs) still carry "AppStackX Reports" in their
hidden document properties: their recorded analyses and demo drafts are keyed to each file's SHA-256,
so rebuilding them means re-recording those. Leave them unless that is worth it. The built-in Word
templates and the sample printed-notes PDF were rebuilt with the new name (their bytes are not keyed).
Extracted from careconnect-mk at ff05fab (branch claude/confident-noether-z6l7kr), where it lived
as a module next to an unrelated patient-portal demo. Brought over: src/modules/medreport,
src/sandbox/tm3-sim, the /reports, /pms-sandbox and API routes, the UI primitives the module
re-exports, scripts/medreport, .env.example and the plan (docs/plan.md, history kept). Left
behind: the portal (landing page, login, dashboard, mock data, its components and assets) and its root
layout with the portfolio banner. Changes made on extraction: a new root layout, / redirect and
not-found page; the banner offset removed from the layouts, the Studio's sticky header and the sticky
side panels; Inter self-hosted through next/font instead of a Google Fonts import; the hard-coded
product name replaced by PRODUCT.name; dependencies trimmed to what the code imports (same versions
as the source lockfile for every direct dependency).
NEXT_PUBLIC_POSTHOG_KEY | Product analytics project key (EU cloud). Unset = no analytics and no cookie banner. Analytics only ever starts after a visitor accepts it in the banner |
NEXT_PUBLIC_POSTHOG_HOST | Optional analytics API host. Default /ingest (proxied to the EU cloud by next.config.mjs, so the browser only talks to our domain) |
NEXT_PUBLIC_POSTHOG_DEBUG | 1 logs the analytics library's activity in the browser console (setup checks only, never in production) |
MAILERSEND_API_KEY, MAILERSEND_FROM_EMAIL | Email via MailerSend. With both set, each "Request access" submission also emails the team; without them requests are only stored |
CLINFORMS_ACCESS_REQUEST_TO | Optional recipient of those emails (default [email protected]) |
PDF_CONVERSION_UNAVAILABLEsrc/modules/medreport/forms/convert.ts