This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Forms Pro is a Frappe app that lets users build forms linked to any Frappe DocType. It has two main parts:
- Backend: Frappe app (
forms_pro/) — Python, doctypes, API endpoints, hooks - Frontend: Vue 3 SPA (
frontend/src/) — served at/forms/, built toforms_pro/public/frontend/
# Development (Vite dev server on port 8080)
npm run dev
# Production build (outputs to forms_pro/public/frontend/)
npm run build
# TypeScript type check
cd frontend && yarn typecheck
# Lint & format (BiomeJS)
cd frontend && yarn lint# Run all app tests
bench --site <site> run-tests --app forms_pro
# Run a specific test module
bench run-tests --module forms_pro.tests.test_rolespre-commit run --all-filesPre-commit runs ruff (Python), prettier (Vue/TS/SCSS), and eslint (JS/TS).
API Layer (forms_pro/api/): Whitelisted Frappe methods callable from the frontend.
form.py— form CRUD, sharing, doctype field introspectionsubmission.py— submit responses, retrieve user submissionsteam.py— team creation, member management, invitationsuser.py— current user, user teams
Doctypes (forms_pro/forms_pro/doctype/):
Form— main form entity; links to any Frappe DocType; hasFormFieldchild table; tracks sharing, publication, success messageFormField— a field in a form; maps to a DocType field; stores conditional logicFPTeam/FPTeamMember— team and membership;FPTeam.usersis aTableMultiSelectofFPTeamMemberFPTeamInvitation— pending team invitations
Form Submission Flow:
api/submission.py:submit_form_response()receives field values- Creates a new document in the linked DocType
- Auto-injects
fp_linked_formandfp_submission_statuscustom fields (created byutils/form_generator.pywhen the form is saved) - Shares the new document with the submitter
Form-DocType Sync (Form.set_doctype_fields()):
When a form is saved, its fields are synced to the linked DocType as CustomField records. Renaming a form field updates the underlying DocType field.
Hooks (hooks.py):
user_invitation.after_accept→overrides/invitations.py— adds invited user to their team server-sidedoc_events["User"].on_update→overrides/roles.py— creates a default team for new Forms Pro users- Website route rule:
/forms/<path:app_path>→www/forms.py(serves the SPA)
Permissions: Form-level access uses Frappe's DocShare. Team membership is stored in FPTeamMember. Always check team.is_team_member(email) before calling team.add_to_team(email) — the latter throws DuplicateEntryError if already a member.
Routing (src/router.ts, base /forms):
| Path | Page | Notes |
|---|---|---|
/ |
Dashboard | Lists user's forms |
/team |
ManageTeam | Team settings/members |
/manage/:id |
ManageForm | Form overview + submissions |
/edit-form/:id |
EditForm | Drag-and-drop form builder |
/p/:route(...) |
SubmissionPage | Public form (allow_guest) |
/p/:route(...)/edit/:submissionName |
PublicEdit | Edit existing submission |
State (src/stores/): Pinia stores.
user.ts— current user, teams list, active team, themeeditForm.ts— form-builder state: selected field, doctype fields availablesubmissionForm.ts— live field values during submissioneditSubmission.ts— values when editing an existing submission
Component Layout:
src/components/builder/— form builder canvas and field editorssrc/components/fields/— per-field-type renderers (Data, Email, Select, Date, etc.)src/components/form/— form rendering (used in submission page)src/components/ui/— generic UI primitivessrc/data/— Frappe resource wrappers (session.ts,user.ts)src/utils/conditionals.ts— evaluates conditional-show logic at runtime
API Calls: Use frappe.call() (via frappe-ui) pointing to the whitelisted Python methods in forms_pro/api/. Guest-accessible endpoints use allow_guest=True in the Python decorator.
| Skill | Description |
|---|---|
/release [version] |
Draft a new GitHub release. Inspects merged PRs since the last release, categorizes them, and creates a draft on GitHub for review. |
- Python target: 3.14+; formatted with
ruff - TypeScript: strict mode;
vue-tscenforced in CI - Frappe patterns: use
frappe.get_doc,frappe.get_all,frappe.db.*; avoid raw SQL unless necessary - PR titles: validated by CI workflow (conventional commit format expected)
- Tests: use Frappe's
IntegrationTestCase; test infrastructure set up ininstall.py:before_tests()