HarborForge.Backend: dev-2026-03-29 -> main #13
Reference in New Issue
Block a user
Delete Branch "dev-2026-03-29"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Automated PR creation for HarborForge submodule development branch.
- New canonical model: Proposal, ProposalStatus (app/models/proposal.py) - New canonical router: /projects/{id}/proposals (app/api/routers/proposals.py) - Schemas renamed: ProposalCreate, ProposalUpdate, ProposalResponse, etc. - Old propose.py and proposes.py kept as backward-compat shims - Legacy /proposes API still works (delegates to /proposals handlers) - DB table name (proposes), column (propose_code), and permission names (propose.*) kept unchanged for zero-migration compat - Updated init_wizard.py comments- Format: {proposal_code}:E{seq:05x} (e.g. PROJ01:P00001:E00001) - Prefix 'E' for Essential, 5-digit zero-padded hex sequence - Sequence scoped per Proposal, derived from max existing code - No separate counter table needed (uses max-suffix approach) - Supports batch_offset for bulk creation during Proposal Accept - Includes validate_essential_code() helper- New router: /projects/{project_id}/proposals/{proposal_id}/essentials - GET (list), POST (create), GET/{id}, PATCH/{id}, DELETE/{id} - All mutations restricted to open proposals only - Permission: creator, project owner, or global admin - Registered essentials router in main.py - Updated GET /proposals/{id} to return ProposalDetailResponse with embedded essentials list - Activity logging on all CRUD operations- Expand RESTRICTED_TYPE_SUBTYPES to include story/feature, story/improvement, story/refactor, and story/None (all story subtypes) - Add FULLY_RESTRICTED_TYPES fast-path set for entire-type blocking - Update _validate_task_type_subtype to block all story types via general create endpoint with clear error message directing to Proposal Accept - Add type/subtype validation to PATCH /tasks/{id} to prevent changing existing tasks to story/* type via update - Internal Proposal Accept flow unaffected (creates tasks directly via ORM)- New service: app/services/plan_slot.py - Virtual slot ID: plan-{plan_id}-{YYYY-MM-DD} format with parse/make helpers - Plan-date matching: on_month/on_week/on_day hierarchy with week_of_month calc - Materialization: convert virtual slot to real TimeSlot row from plan template - Detach: clear plan_id after edit/cancel to break plan association - Bulk materialization: materialize_all_for_date for daily pre-compute - New tests: tests/test_plan_slot.py (23 tests, all passing)- Add TimeSlotEdit schema (partial update, all fields optional) - Add TimeSlotEditResponse schema - Add PATCH /calendar/slots/{slot_id} for editing real slots - Add PATCH /calendar/slots/virtual/{virtual_id} for editing virtual slots - Triggers materialization before applying edits - Detaches from plan after edit - Both endpoints enforce past-slot immutability, overlap detection, plan detachment, and workload warnings- Add POST /calendar/slots/{slot_id}/cancel for real slot cancellation - Add POST /calendar/slots/virtual/{virtual_id}/cancel for virtual slot cancellation - Virtual cancel materializes the slot first, then marks as Skipped - Both endpoints enforce past-slot immutability guard - Both endpoints detach from plan (set plan_id=NULL) - Status set to SlotStatus.SKIPPED on cancel - Add TimeSlotCancelResponse schema- Add SchedulePlanCreate, SchedulePlanResponse, SchedulePlanListResponse schemas - Add DayOfWeekEnum, MonthOfYearEnum schema enums - Add POST /calendar/plans endpoint (create plan with hierarchy validation) - Add GET /calendar/plans endpoint (list plans, optional include_inactive) - Add GET /calendar/plans/{plan_id} endpoint (get single plan)- PATCH /calendar/plans/{plan_id}: edit a recurring schedule plan - Validates period-parameter hierarchy after merge - Rejects edits to inactive (cancelled) plans - Detaches future materialized slots so they keep old data - Past materialized slots remain untouched - POST /calendar/plans/{plan_id}/cancel: cancel (soft-delete) a plan - Sets is_active=False - Detaches future materialized slots (plan_id -> NULL) - Preserves past materialized slots, returns their IDs - Added SchedulePlanEdit and SchedulePlanCancelResponse schemas