§22 M3-backend Plan B (write path, propose): project-scoped propose (v0.38.0)
A new entry can be proposed into a specific project; it lands in that project's
content repo and shows under that project's proposals. A non-default project is
no longer read-only.
- api.py: POST /api/projects/{pid}/rfcs/propose (propose body extracted into a
project-parameterized helper; unscoped /api/rfcs/propose kept as default
compat). Slug uniqueness, idea-PR reservation, landing state, and the
proposed_use_cases row scoped to the target project. GET
/api/projects/{pid}/proposals.
- cache.py: refresh_meta_pulls loops every project's content_repo, stamping
cached_prs.project_id; projects.content_repo(pid) helper.
- frontend: proposeRFC(projectId,…)/listProposals(projectId); ProposeModal
takes projectId; App resolves current project from the /p/<id>/ URL; Catalog
lists that project's proposals.
- tests: test_project_scoped_propose.py (lands scoped + gated 404). 447 backend
+ 11 Vitest green; clean build.
Known limitation: branch/PR/graduation edit flows + default-id re-stamp not yet
scoped (next slice). Per docs/superpowers/specs/2026-06-04-m3-backend-planb-design.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -61,6 +61,11 @@ export default function App() {
|
||||
// §22.9 — runtime deployment config (name for the brand, default project id
|
||||
// for building corpus links this slice; see DeploymentProvider).
|
||||
const deployment = useDeployment()
|
||||
// §22.4 — the project the viewer is currently in (from the /p/<id>/ URL),
|
||||
// so the propose modal (App-level chrome, above the route tree) targets the
|
||||
// right project. Falls back to the deployment default off a project route.
|
||||
const _projMatch = location.pathname.match(/^\/p\/([^/]+)/)
|
||||
const currentProjectId = (_projMatch && _projMatch[1]) || deployment.defaultProjectId
|
||||
// #28 Parts 2–3: the LinkedText create/contribute affordances route via
|
||||
// query params so they need no prop-threading from deep in a comment
|
||||
// list. `?propose=<term>` opens the propose modal pre-filled;
|
||||
@@ -372,12 +377,13 @@ export default function App() {
|
||||
<ProposeModal
|
||||
viewer={viewer}
|
||||
initialTitle={proposeParam || ''}
|
||||
projectId={currentProjectId}
|
||||
onClose={() => { setProposeOpen(false); clearParams('propose') }}
|
||||
onSubmitted={({ pr_number }) => {
|
||||
setProposeOpen(false)
|
||||
clearParams('propose')
|
||||
setCatalogVersion(v => v + 1)
|
||||
navigate(proposalPath(deployment.defaultProjectId, pr_number))
|
||||
navigate(proposalPath(currentProjectId, pr_number))
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user