PRD — frappe-stack¶
Product Requirements Document. Owns the what and why. Pairs with
PLAN.md(the how) andSECURITY.md(the must-not).
1. Problem¶
Building Frappe apps today requires a developer for every change. PMs, analysts, and business analysts have to:
- File a ticket, wait for a developer to add a DocType / Custom Field / Workflow.
- Trust that the developer remembered fixtures (so the change ships with the app).
- Trust that permissions, audit log, and site-vs-app-fixture conflicts were handled.
This forces non-developers into manual workarounds (spreadsheets, paper forms, off-platform approvals). Meanwhile, even when developers do the work, site changes routinely drift from GitHub — the audit trail is the change log of a single site, not git history.
2. Users & their jobs¶
Primary: PM / Analyst (non-developer)¶
"I need to add a beneficiary registration form with three approval levels and a dashboard. I don't want to write Python."
Jobs: - Create DocTypes, Custom Fields, Workflows, Dashboards, Reports, Configs. - See what they built committed to GitHub automatically. - Promote staging changes to production with confidence (review + approval). - Run A/B experiments on workflows to compare approval paths.
Secondary: Developer / DevOps¶
Jobs: - Review PM-generated PRs before merge to production. - Trust that the plugin already enforced security/best-practice — review = sanity check, not full audit. - Diff site state vs git state when troubleshooting.
Tertiary: Director / Compliance¶
Jobs:
- Audit every change via git history + Frappe's built-in Activity Log + the local .frappe-stack/audit.jsonl on PM machines.
- Confirm no PII bypass, no ignore_permissions=True, no hard deletes.
3. Solution shape¶
3.1 One layer¶
The Claude Code plugin (frappe-stack) — slash commands, skills, agents, safety hooks. PM types intent; plugin generates correct config and POSTs it to Frappe's stock REST API. Nothing custom-installed on the Frappe site (D-10 confirmed 2026-05-05).
The plugin still includes the four Experiment Assignment, A/B Custom Field, and Server Script primitives — but those are created on demand via stock POST /api/resource, the first time you run /frappe-stack:experiment define. They are normal Frappe DocTypes / Custom Fields / Server Scripts, not a custom Frappe app.
3.2 Sync model — B+ hybrid (D-01 confirmed)¶
%%{init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#F5E6DD',
'primaryTextColor': '#2E2E2E',
'primaryBorderColor': '#8B1E24',
'lineColor': '#9E2A2F',
'secondaryColor': '#E7C1AD',
'tertiaryColor': '#ffffff',
'fontFamily': 'Inter, system-ui, sans-serif',
'fontSize': '13px'
}
}}%%
flowchart LR
PM["PM types in<br>Claude Code"]
Build[/frappe-stack:build/]
Stage[("Staging site<br>stock Frappe v15+")]
Pull[/frappe-stack:pull/]
Repo[("GitHub config repo<br>versioned JSON<br>per blueprint")]
Promote[/frappe-stack:promote/]
PR{"PR review<br>merge"}
CI[Operator CI runs<br>bench migrate]
Prod[("Production site<br>git-only")]
PM --> Build
Build -->|"POST /api/resource/<DocType>"| Stage
Stage --> Pull
Pull -->|"per-blueprint JSONs"| Repo
Repo --> Promote
Promote --> PR
PR --> CI
CI --> Prod
classDef cmd fill:#F5E6DD,stroke:#8B1E24,stroke-width:1.5px,color:#2E2E2E,rx:10,ry:10
classDef store fill:#ffffff,stroke:#8B1E24,stroke-width:1.5px,color:#2E2E2E
classDef gate fill:#F28C38,stroke:#9E2A2F,stroke-width:1.5px,color:#ffffff
classDef plain fill:#ffffff,stroke:#D9B3A0,stroke-width:1px,color:#6B6B6B
class Build,Pull,Promote cmd
class Stage,Repo,Prod store
class PR gate
class PM,CI plain
- Staging is the playground — fast iteration via stock REST.
- Production is git-only — the audit trail is git history.
/frappe-stack:promoteis the bridge: snapshots staging via stock REST, writes per-blueprint JSONs to the config repo, opens a PR, lets a reviewer approve, merges, triggers prod migrate via the operator's existing CI/CD.
3.3 A/B experiments in workflows¶
A split state in Frappe Workflow with deterministic traffic assignment by hash(experiment_id || doc.name). Implemented as stock primitives — Custom Field on the target DocType, Server Script on workflow state-change, regular Experiment Assignment DocType for tracking. Created by /frappe-stack:experiment define via POST /api/resource/.... Promotable via /frappe-stack:experiment promote arm_a, which strips the losing arm from the workflow JSON and opens a PR.
Full spec in PLAN.md §8.
4. Non-goals¶
- Replacing Frappe's Form Builder UI. We call it.
- Cross-Frappe-version magic. We target Frappe v15+ only.
- Multi-tenant federation. One plugin install = one stack of (staging, prod) sites.
- Generic workflow engine. Only Frappe Workflow extensions.
5. Success metrics (post-MVP)¶
| Metric | Target |
|---|---|
| Time from PM intent → DocType live on staging | < 5 minutes |
| % of site changes reflected in git within 1 commit | 100% (enforced — non-negotiable) |
% of PR-promoted changes that pass frappe-semgrep-rules |
100% (block at hook) |
ignore_permissions=True instances introduced via plugin |
0 (block at hook) |
allow_guest=True instances introduced via plugin |
0 (block at hook) |
6. Out of scope for v0.1¶
infra/(Docker compose, CI workflows, pre-commit) — deferred per stakeholder direction.- Mobile/Flutter integration (
frappe-mobile-sdkalready exists separately). - Print format builder (Frappe core handles this).
- Multi-language UI (Frappe
__()is enough for now).
7. Inspiration & prior art¶
sunandan89/mgrant-frappe-patterns— patterns catalog to absorb into ourfrappe-patternsskill (when public).dhwani-ris/frappe_dhwani_base— ruff/eslint/prettier/pyupgrade pre-commit + Frappe Semgrep + pip-audit setup, when we get toinfra/.gavindsouza/awesome-frappe— survey before building anything new.- The structural pattern (Claude Code plugin shipping skills/agents/commands/hooks for a Frappe codebase) was adapted from an internal reference that informs the layout and naming conventions used here.