# Design Document ## Overview This design implements a database schema enhancement to add a `project_id` column to the shots table, establishing a direct relationship between shots and projects. This change improves data integrity, enables project-scoped shot name uniqueness, and provides better query performance for project-based shot operations. ## Architecture The enhancement follows a layered approach: 1. **Database Layer**: Add project_id column with foreign key constraint and index 2. **Model Layer**: Update SQLAlchemy Shot model with project relationship 3. **Schema Layer**: Update Pydantic schemas to include project_id 4. **API Layer**: Modify endpoints to handle project_id in requests/responses 5. **Service Layer**: Update business logic for project-scoped validation 6. **Frontend Layer**: Update TypeScript interfaces and components ## Components and Interfaces ### Database Schema Changes ```sql -- Add project_id column to shots table ALTER TABLE shots ADD COLUMN project_id INTEGER; -- Create foreign key constraint ALTER TABLE shots ADD CONSTRAINT fk_shots_project_id FOREIGN KEY (project_id) REFERENCES projects(id); -- Create index for performance CREATE INDEX idx_shots_project_id ON shots(project_id); -- Create composite index for project-scoped name uniqueness CREATE UNIQUE INDEX idx_shots_project_name_unique ON shots(project_id, name) WHERE deleted_at IS NULL; ``` ### Model Updates **Shot Model (backend/models/shot.py)**: - Add `project_id` column as non-nullable foreign key - Add `project` relationship to Project model - Update uniqueness constraints to be project-scoped - Maintain backward compatibility with episode relationship **Project Model (backend/models/project.py)**: - Add `shots` relationship back-reference ### Schema Updates **ShotBase Schema**: - Add optional `project_id` field for API flexibility - Maintain episode_id as primary relationship identifier **ShotResponse Schema**: - Include `project_id` in all response payloads - Add computed `project_name` field for frontend convenience ### API Endpoint Changes **Shot Creation Endpoints**: - Automatically derive `project_id` from `episode_id` - Validate project consistency between episode and provided project_id - Update uniqueness validation to be project-scoped **Shot Query Endpoints**: - Add optional `project_id` filter parameter - Include project information in response payloads - Maintain existing episode-based filtering ## Data Models ### Updated Shot Model Structure ```python class Shot(Base): __tablename__ = "shots" id = Column(Integer, primary_key=True, index=True) project_id = Column(Integer, ForeignKey("projects.id"), nullable=False, index=True) episode_id = Column(Integer, ForeignKey("episodes.id"), nullable=False) name = Column(String, nullable=False, index=True) # ... other existing fields # Relationships project = relationship("Project", back_populates="shots") episode = relationship("Episode", back_populates="shots") # ... other existing relationships # Constraints __table_args__ = ( UniqueConstraint('project_id', 'name', name='uq_shot_project_name'), ) ``` ### Frontend Interface Updates ```typescript interface Shot { id: number project_id: number episode_id: number name: string // ... other existing fields // Optional computed fields project_name?: string } interface ShotCreate { name: string project_id?: number // Optional, derived from episode if not provided // ... other existing fields } ``` ## Correctness Properties *A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.* ### Property 1: Project-Episode Consistency *For any* shot in the system, the project_id must match the project_id of its associated episode **Validates: Requirements 1.2, 3.3, 4.2** ### Property 2: Project-Scoped Name Uniqueness *For any* project, shot names must be unique within that project scope (excluding soft-deleted shots) **Validates: Requirements 1.1, 1.4** ### Property 3: API Response Completeness *For any* shot API response, the response must include both the project_id field and all previously existing fields **Validates: Requirements 1.3, 3.1, 4.1** ### Property 4: Migration Data Preservation *For any* existing shot before migration, the shot data after migration should be identical except for the addition of the correct project_id derived from the episode relationship **Validates: Requirements 2.4, 2.5** ### Property 5: Project Filtering Accuracy *For any* project_id filter parameter, the API should return only shots that belong to that specific project **Validates: Requirements 3.4** ### Property 6: Bulk Operation Consistency *For any* bulk shot creation operation, all created shots must have the same project_id as their target episode **Validates: Requirements 3.5** ### Property 7: Soft Deletion Project Preservation *For any* shot that undergoes soft deletion, the project_id must be preserved for recovery operations **Validates: Requirements 4.5** ### Property 8: Permission System Continuity *For any* shot operation that was previously authorized, the same operation should remain authorized after the schema change **Validates: Requirements 4.4** ## Error Handling ### Migration Errors - **Orphaned Episodes**: Handle episodes without valid project references - **Data Inconsistency**: Detect and report shots with mismatched episode-project relationships - **Constraint Violations**: Handle existing duplicate shot names within projects ### Runtime Errors - **Invalid Project ID**: Return 400 Bad Request for non-existent project references - **Project-Episode Mismatch**: Return 400 Bad Request when provided project_id doesn't match episode's project - **Duplicate Shot Names**: Return 409 Conflict for project-scoped name collisions ### Frontend Error Handling - **Migration Status**: Display migration progress and handle temporary unavailability - **Validation Errors**: Show clear messages for project-scoped naming conflicts - **Fallback Behavior**: Gracefully handle missing project information during transition ## Testing Strategy ### Unit Tests - Test Shot model creation with project_id - Test project-scoped uniqueness validation - Test API endpoint parameter handling - Test schema serialization/deserialization ### Property-Based Tests - **Property 1 Test**: Generate random shots and verify project-episode consistency - **Property 2 Test**: Generate random shot names within projects and verify uniqueness enforcement - **Property 3 Test**: Create test data, run migration simulation, verify data preservation - **Property 4 Test**: Generate shots with various project_id values and verify foreign key constraints - **Property 5 Test**: Generate API requests in old format and verify response compatibility ### Integration Tests - Test complete shot creation workflow with project validation - Test shot querying with project filtering - Test bulk shot creation with project consistency - Test soft deletion with project_id preservation ### Migration Tests - Test migration script with various data scenarios - Test rollback procedures - Test performance with large datasets - Test constraint creation and validation The testing approach uses **Pytest** for the Python backend with **Hypothesis** for property-based testing. Each property-based test will run a minimum of 100 iterations to ensure comprehensive coverage of the input space.