A Hebrew-first web application providing information, self-help tools, and support resources for PTSD trauma survivors and their families in Israel. Supports 5 languages (Hebrew, Arabic, Russian, English, French) with full RTL.
- Self-help tools - guided breathing, grounding (5-4-3-2-1), progressive muscle relaxation
- PTSD screening - anonymous self-assessment questionnaire (PCL-based)
- Treatment pathways - step-by-step guidance through therapeutic options
- Rights & bureaucracy - legal rights, disability support, compensation processes
- Children's content - age-appropriate trauma education
- Community groups - connecting survivors with local support groups
- Admin dashboard - content management interface (requires backend, TBD)
Two user journeys: survivors (first circle) and their loved ones (second circle).
- Frontend - React 18, React Router 6, Vite 6
- Styling - Tailwind CSS, Radix UI, Framer Motion
- State - TanStack React Query
- Forms - React Hook Form + Zod
- Other - Three.js, Recharts, Leaflet, jsPDF, Stripe
cd src
npm install
npm run dev # dev server at localhost:5173
npm run build # production build
npm run lint # ESLint
npm run typecheck # type checkingThe site is a Render static site served from the domain root. (It previously ran on GitHub Pages under /PTSD.IL/; that's retired.)
- Render config: root directory
src, build commandnpm install && npm run build, publish directorydist. src/base-path.jsexportsBASE_PATH = ''(root) - consumed byvite.config.js(buildbase) andApp.jsx(Routerbasename).VITE_API_URLmust be set in the Render dashboard (baked in at build time).- An SPA rewrite rule (
/*->/index.html) is configured so deep links and refresh work. - Render auto-deploys from
masteron push. Commit tomaster; the owner pushes when ready.
/
├── src/ # React app
│ ├── pages/ # Route components - UI structure only, no inline content
│ ├── components/ # UI components (Radix wrappers + custom)
│ ├── lib/ # Language/theme contexts + i18n.js (UI strings)
│ ├── data/ # static/ + db.js - RETIRED, kept only for the questionnaire
│ ├── api/
│ │ ├── source.js # public read adapters (API -> page shapes)
│ │ ├── hooks.js # React Query hooks - what pages use to read data
│ │ ├── adminClient.js# authenticated fetch wrapper (Bearer JWT)
│ │ └── adminSource.js# admin CRUD layer
│ ├── hooks/
│ └── utils/
├── docs/ # api.md (backend contract), mobile-data-guide.md, specs
└── entities/ # legacy DB entity schemas (JSON)
The site is backed by a live API gateway (a headless-CMS-style backend over a database) at https://ptsd-il-api.onrender.com/api. The backend code is not in this repo - it's a black box we call over HTTP. Its full contract is in docs/api.md; the content model (for the mobile app or any consumer) is in docs/mobile-data-guide.md.
The DB stores content as pure data: each row is one content item in one language, and the item's payload is a JSON string (the content column) with Markdown in every rich-text field - never HTML. The frontend parses that JSON and applies all styling. This is deliberate: the same data drives this website and the future mobile app, each rendering it however it wants.
- One row = one item per language.
typedistinguishes the kind (faq,tool,treatment_step,source,book,article, ...). - Translations of the same item share a
groupId. Taxonomy (categories / audiences / age-groups) is referenced by slug. - Only the FAQs are translated (he/ar/en); everything else is Hebrew-only;
ru/frare empty and fall back to Hebrew.
src/pages/*.jsx <- render; rich text via <Markdown> (react-markdown)
src/api/hooks.js <- React Query hooks (useSources, useRightsFaqs, ...)
src/api/source.js <- fetch* adapters: GET the API, JSON.parse content,
reshape into the shape each page expects
src/api/source.js is the single integration layer - it fetches from the API and maps each response to the page shape. Rich Markdown fields render through src/components/Markdown.jsx (internal /... links become router links; external open in a new tab).
Content is edited through the admin panel, behind login:
- Auth (
src/lib/auth.js,src/pages/AdminLogin.jsx): email/password -> JWT (POST /api/auth/login), stored insessionStorage. The/adminroute guard (AdminGateinApp.jsx) is UX only - authorization is enforced server-side by the backend re-checking the JWT + role on every write. - Writes (
src/api/adminSource.js,src/api/adminClient.js): each panel loads from the API and does real create/update/delete.src/lib/markdownHtml.jsconverts between the react-quill HTML editor and the DB's Markdown on save/load.
src/data/static/* + src/data/db.js used to be the mock "database" and are now retired. They remain only for the PCL-5 questionnaire, which has no API endpoint yet (Questionnaire.jsx and the read-only admin questionnaire panel still read db), and as the historical source the DB was migrated from. New content goes through the API/admin, not here.
src/lib/i18n.js still holds UI strings (button labels, nav, headings) via t(lang, 'key') with Hebrew fallback. That's distinct from content, which comes from the API. Rule of thumb: interface chrome -> i18n.js; anything a content editor would manage -> the API/admin.
- Replace all content with validated content (reviewed by professionals/verified sources)
- Make every piece of content dynamic - move all content to a database so the site parses data from it, enabling updates without code changes
- Change the background texture - pick the best one along with the best matching color palette
- Create a full design system/theme from the site that will serve as the foundation for the mobile application development
The backend API gateway has shipped and the site now reads/writes live data (the
"When the real backend ships" note above is largely historical — src/api/source.js
now fetches from the API instead of static db). Content is stored as pure data:
each article's content is a JSON string with Markdown leaves; the UI renders
the styling. The admin panel (/admin) is behind login and does real CRUD. These
items are known-incomplete and should be revisited:
- Auth is temporary password login, not SSO. Move admin auth to Google SSO
(
POST /api/auth/googleon the BE + a sign-in button) — the current flow slots out cleanly. Note: authentication and role checks are enforced server-side via JWT on every/api/admin/*call; the client-side/adminroute guard is UX only (show/hide), not a security boundary. - New admin items don't link translations. Creating a new FAQ in one language
makes a single-language item (fresh
groupId). Editing/deleting existing translated items works. Add translation-linked creation (create he + ar + en sharing onegroupId). - Community target-audiences may not persist on save. The API docs don't
document how to set
targetAudiencesonPOST/PUT /api/admin/communities; the admin wires it by analogy but it's unverified. Confirm the field name / BE support. - Treatment
methodsand self-helpappsaren't editable in the admin UI. They're carried through as passthrough data (edits don't strip them) but there are no form controls to edit them yet. Add UI. - Questionnaire admin panel is read-only. The PCL-5 questionnaire has no API endpoint, so it still reads the static file and can't be edited. Add a BE endpoint + migrate it, then wire the panel.
- No
ru/frcontent in the DB. Those languages fall back to Hebrew. Add translations (or hide the language options until content exists). - Deployment note: the "Deployment (GitHub Pages)" section above is stale —
the site is now a Render static site served from the domain root (
BASE_PATHis''), withVITE_API_URLset in the Render dashboard.