PROBLEM: Simple full_rest/active_recovery model doesn't support
context-specific rest days (e.g., strength rest but cardio allowed).
SOLUTION: JSONB-based flexible rest day configuration.
## Changes:
**Migration 010:**
- Refactor rest_days.type → rest_config JSONB
- Schema: {focus, rest_from[], allows[], intensity_max}
- Validation function with check constraint
- GIN index for performant JSONB queries
**Backend (routers/rest_days.py):**
- CRUD: list, create (upsert by date), get, update, delete
- Stats: count per week, focus distribution
- Validation: check activity conflicts with rest day config
**Frontend (api.js):**
- 7 new methods: listRestDays, createRestDay, updateRestDay,
deleteRestDay, getRestDaysStats, validateActivity
**Integration:**
- Router registered in main.py
- Ready for weekly planning validation rules
## Next Steps:
- Frontend UI (RestDaysPage with Quick/Custom mode)
- Activity conflict warnings
- Dashboard widget
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
63 lines
2.2 KiB
PL/PgSQL
63 lines
2.2 KiB
PL/PgSQL
-- Migration 010: Rest Days Refactoring zu JSONB
|
|
-- v9d Phase 2a: Flexible, context-specific rest days
|
|
-- Date: 2026-03-22
|
|
|
|
-- Refactor rest_days to JSONB config for flexible rest day types
|
|
-- OLD: type VARCHAR(20) CHECK (type IN ('full_rest', 'active_recovery'))
|
|
-- NEW: rest_config JSONB with {focus, rest_from[], allows[], intensity_max}
|
|
|
|
-- Drop old type column
|
|
ALTER TABLE rest_days
|
|
DROP COLUMN IF EXISTS type;
|
|
|
|
-- Add new JSONB config column
|
|
ALTER TABLE rest_days
|
|
ADD COLUMN IF NOT EXISTS rest_config JSONB NOT NULL DEFAULT '{"focus": "mental_rest", "rest_from": [], "allows": []}'::jsonb;
|
|
|
|
-- Validation function for rest_config
|
|
CREATE OR REPLACE FUNCTION validate_rest_config(config JSONB) RETURNS BOOLEAN AS $$
|
|
BEGIN
|
|
-- Must have focus field
|
|
IF NOT (config ? 'focus') THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
|
|
-- focus must be one of the allowed values
|
|
IF NOT (config->>'focus' IN ('muscle_recovery', 'cardio_recovery', 'mental_rest', 'deload', 'injury')) THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
|
|
-- rest_from must be array if present
|
|
IF (config ? 'rest_from') AND jsonb_typeof(config->'rest_from') != 'array' THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
|
|
-- allows must be array if present
|
|
IF (config ? 'allows') AND jsonb_typeof(config->'allows') != 'array' THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
|
|
-- intensity_max must be number between 1-100 if present
|
|
IF (config ? 'intensity_max') AND (
|
|
jsonb_typeof(config->'intensity_max') != 'number' OR
|
|
(config->>'intensity_max')::int < 1 OR
|
|
(config->>'intensity_max')::int > 100
|
|
) THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
|
|
RETURN TRUE;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Add check constraint
|
|
ALTER TABLE rest_days
|
|
ADD CONSTRAINT valid_rest_config CHECK (validate_rest_config(rest_config));
|
|
|
|
-- Add comment for documentation
|
|
COMMENT ON COLUMN rest_days.rest_config IS 'JSONB: {focus: string, rest_from: string[], allows: string[], intensity_max?: number (1-100), note?: string}';
|
|
COMMENT ON TABLE rest_days IS 'v9d Phase 2a: Context-specific rest days (strength rest but cardio allowed, etc.)';
|
|
|
|
-- Create GIN index on rest_config for faster JSONB queries
|
|
CREATE INDEX IF NOT EXISTS idx_rest_days_config ON rest_days USING GIN (rest_config);
|