Every area lives under frontend/apps/saas/app/(authenticated)/(main)/(organizations)/[organizationSlug]/. Paths on this page are relative to that folder unless they start with modules/. Each area follows the same shape: page.tsx loads, a client view renders, actions.ts writes, and pure model files (with tests next to them) hold the logic. See Server actions.

Trainee board

The master detail screen for trainees.

Plan builders

Training and nutrition builders, file plans, import.

Work board and automations

Tasks, the task panel and the flow builder.

Uploads

How files get from the browser to storage.

Dashboard

DashboardView receives the overview, the coach’s name and the studio’s accent colour. loadDashboard(slug, period) reloads it for another period. markInboxStatus and bulkInbox update task rows shown on the home screen, and searchTrainees powers the quick search (six results). The AutoFit sync bar is a manager only band at the top of the home screen. The page reads the sync run on the server together with two cookies (AFSYNC_HIDDEN_COOKIE, AFSYNC_CLOSED_COOKIE) so a hidden bar never flashes. loadAutofitSync is its polling action and never throws. /{slug}/inbox still exists as a route and only redirects here.

Trainees

Route /{slug}/clients. Covered in Trainee board. clients/[clientId]/ no longer has a card page. page.tsx permanently redirects to the board with ?client=. The folder still holds components the board’s detail pane uses: ProgramsTab.tsx, PlanBanner.tsx, AddSubscriptionDialog.tsx, FoodPreferencesDialog.tsx, PdfPlanAssignForm.tsx, and the trainee level actions.ts (subscriptions, programs, form assignment, freeze and reactivate).

Training and nutrition plans

Routes /{slug}/templates?scope=training, /{slug}/templates?scope=nutrition, /{slug}/templates/[id]/edit and /{slug}/clients/[clientId]/programs/[programId]/edit. Covered in Plan builders.

Exercise library

A table with inline editing (use-inline-save.ts), filters and a detail dialog. Videos upload through the shared chunked relay with scope: "exercises".

Food library

The page reads /foods and the studio settings. isMbpEnabled, mbpAnchors and mbpUnitLabel from modules/shared/lib/studio-settings.ts decide whether the portion (MBP) columns show. The list is cached client side under ["food-library", slug].

Forms

The builder

FormEditor is the three column editor: FieldPalette, BuilderCanvas and FieldEditorPanel, with BuilderTopBar, FormSettingsDialog and a live FormSimulator that renders the form as the trainee app would. form-schema.ts lists the 25 field types in FORM_FIELD_TYPES: text, number, phone, israeli_id, age, height, weight, body_measurement, goal, email, gender, date, birth_date, dropdown, checkbox_confirmation, rating, range, image_upload, video_upload, food_preferences, read_more, coach_message, text_block, media_block and signature. Display only types carry no answer and are never required. A field kind is described in four places. Touch all of them when adding one:
  1. The FormFieldType union in perform-types.ts and the lists and helpers in form-schema.ts (FORM_FIELD_TYPES, DISPLAY_ONLY_TYPES, CLIENT_SAVE_TYPES, OPTION_TYPES).
  2. The palette entry in forms/builder/field-defs.ts. An entry with hidden: true is retired from the palette but still renders in existing forms.
  3. The settings panel in FieldTypeSettings.tsx and the canvas preview in FieldControlPreview.tsx.
  4. The simulator in SimulatorField.tsx.
If the type can be the source of a condition, also add it to form-conditions.ts.

Conditions

form-conditions.ts is the conditions engine: isConditionMet, isFieldVisible, isPageVisible, visiblePageIndexes, isFieldAnswerable and stripHiddenAnswers. conditionSourceKind(type) classifies a field as numeric, date, choice, boolean or presence, and operatorsForType lists the operators that make sense for it. conditionFromLegacyVisibleIf upgrades the older single condition format. The same engine exists in the backend (backend/apps/core-api/src/modules/forms/form-conditions.ts) and in the mobile app (mobile/src/features/forms/lib/conditions.ts). A change here must be mirrored in both.

PDF signature forms

A template of type PDF signature opens PdfSignEditor instead of FormEditor. The coach places fields on the pages of an uploaded PDF. pdf.js reads the source through /api/forms/templates/[id]/document. The trainee signs at /sign/[token] (modules/sign).

Actions

forms/actions.ts: createForm, updateForm, savePdfSignForm, deleteForm, duplicateForm, uploadFormMedia, getFormResponseSummary, getFoodCatalog, analyzeFormsAi and getFormsAiJob. Sending a form to a trainee goes through assignForm in clients/[clientId]/actions.ts. It returns an ApiResult, and an inactive form is refused with details.reason === "FORM_INACTIVE".

Check-ins

The queue page makes one request, /checkins with status=all, type=all and sort=wait_desc. All filtering (status chips, type segments, search, date ranges, stat cards) happens in the browser. Counts, the admin flag and the coach list come back on the same response. The review route loads one check-in and the list around it, studio settings and the chat embed config. It is a canvas route: the sidebar collapses on entry. Actions in checkin/actions.ts include sendCheckinFeedback, saveCheckinDraft, reassignCheckin, deleteCheckins, remindCheckin, requestTechniqueVideo, and the lazy loaders fetchCheckinTracking, fetchCheckinInsights, fetchCheckinPlansData and fetchCheckinClientData. The schedule math for the next check-in date is in modules/shared/lib/check-in-schedule.ts, with tests beside it.

Content

ContentEditor registers with the unsaved changes guard and validates required fields on save. content/actions.ts covers items (/content), media (/content/media), categories, tags and recipe generation (/content/generate-recipe). The home banner (content/home-banner/) has its own view, form and app preview. One banner exists per studio.

Work board and automations

Routes /{slug}/workboard and /{slug}/automations. Covered in Work board and automations.

Calendar

The page returns notFound() when isCalendarEnabled(studio.settings) is false, and the sidebar hides the item for the same reason. The default coach filter is the only coach when the studio has one, otherwise all.

CRM

The board reads /crm/board. Converting a lead creates a trainee, so it can hit the plan’s trainee limit and open PlanLimitDialog.

Assistant

A full screen chat for the coach. The page loads the current thread from /assistant/thread.

Team

Route /{slug}/coaches. See Organizations and roles. Files: CoachesView.tsx, TeamMemberDialog.tsx, DismissTeamMemberDialog.tsx, team-permissions.ts, last-active.ts.

Branding

The editor reads /studios/current, writes with a PATCH to the same path and shows a phone preview. Logos upload through orpc.organizations.createBrandLogoUploadUrl. See Theming for how the saved branding reaches the page.

Studio settings

Public signing page

Not a coach screen, but it ships in this app. The trainee sees the PDF, fills the placed fields, draws a signature and submits. Relays are described in Route handlers.

Super admin

Routes under /admin. Files in app/(authenticated)/(main)/(account)/admin/ and modules/admin/. The default form templates screen reuses the studio FormEditor.

Shared domain models

Pure modules in modules/shared/lib that several areas import. Most have a test file beside them. Logic that also exists in the backend or the mobile app, such as form conditions, must stay in step with those copies. There is no shared package between the three repos for it.