mirror of https://github.com/docusealco/docuseal
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
906 lines
29 KiB
906 lines
29 KiB
# Story 1.2: Core Models Implementation
|
|
|
|
## Status
|
|
|
|
Approved
|
|
|
|
---
|
|
|
|
## Story
|
|
|
|
**As a** developer,
|
|
**I want** to create ActiveRecord models for the new FloDoc tables,
|
|
**so that** the application can interact with cohorts and enrollments programmatically.
|
|
|
|
---
|
|
|
|
## Background
|
|
|
|
Models must follow existing DocuSeal patterns:
|
|
- Inherit from `ApplicationRecord`
|
|
- Use `strip_attributes` for data cleaning
|
|
- Include soft delete functionality
|
|
- Define proper associations and validations
|
|
- Follow naming conventions
|
|
|
|
**Key Requirements from PRD:**
|
|
- FR1: Create Institution model with single-record pattern
|
|
- FR2: Create Cohort model with state machine for 5-step workflow
|
|
- FR3: Create CohortEnrollment model with status tracking
|
|
- FR4: Feature flag system for FloDoc functionality
|
|
- FR5: All models must integrate with existing DocuSeal tables
|
|
|
|
**Integration Points:**
|
|
- `Cohort.institution_id` → references `institutions.id` (new table)
|
|
- `Cohort.template_id` → references `templates.id` (existing DocuSeal table)
|
|
- `CohortEnrollment.cohort_id` → references `cohorts.id` (new table)
|
|
- `CohortEnrollment.submission_id` → references `submissions.id` (existing DocuSeal table)
|
|
|
|
---
|
|
|
|
## Tasks / Subtasks
|
|
|
|
- [ ] Task 1: Create FeatureFlag model and concern (AC: 7, 8, 9)
|
|
- [ ] Subtask 1.1: Create `app/models/feature_flag.rb` with enabled?, enable!, disable! methods
|
|
- [ ] Subtask 1.2: Create `app/controllers/concerns/feature_flag_check.rb` concern
|
|
- [ ] Subtask 1.3: Create migration `db/migrate/20260116000001_create_feature_flags.rb`
|
|
- [ ] Subtask 1.4: Seed default flags (flodoc_cohorts, flodoc_portals)
|
|
- [ ] Subtask 1.5: Write model spec for FeatureFlag
|
|
|
|
- [ ] Task 2: Create Institution model (AC: 1, 2, 3, 4)
|
|
- [ ] Subtask 2.1: Create `app/models/institution.rb`
|
|
- [ ] Subtask 2.2: Define associations (has_many :cohorts)
|
|
- [ ] Subtask 2.3: Implement validations (name, email presence + format)
|
|
- [ ] Subtask 2.4: Implement scopes (active)
|
|
- [ ] Subtask 2.5: Implement class method `.current`
|
|
- [ ] Subtask 2.6: Include SoftDeletable module
|
|
- [ ] Subtask 2.7: Write model spec for Institution
|
|
|
|
- [ ] Task 3: Create Cohort model with state machine (AC: 1, 2, 3, 4, 5)
|
|
- [ ] Subtask 3.1: Create `app/models/cohort.rb`
|
|
- [ ] Subtask 3.2: Define associations (belongs_to :institution, :template; has_many :cohort_enrollments)
|
|
- [ ] Subtask 3.3: Implement validations (name, program_type, sponsor_email, status)
|
|
- [ ] Subtask 3.4: Implement scopes (active, draft, ready_for_sponsor, completed)
|
|
- [ ] Subtask 3.5: Implement AASM state machine for 7 states
|
|
- [ ] Subtask 3.6: Implement state transition events
|
|
- [ ] Subtask 3.7: Implement instance methods (all_students_completed?, sponsor_access_ready?, tp_can_sign?)
|
|
- [ ] Subtask 3.8: Include SoftDeletable module
|
|
- [ ] Subtask 3.9: Write model spec for Cohort
|
|
|
|
- [ ] Task 4: Create CohortEnrollment model (AC: 1, 2, 3, 4)
|
|
- [ ] Subtask 4.1: Create `app/models/cohort_enrollment.rb`
|
|
- [ ] Subtask 4.2: Define associations (belongs_to :cohort, :submission)
|
|
- [ ] Subtask 4.3: Implement validations (student_email, status, role, submission_id uniqueness)
|
|
- [ ] Subtask 4.4: Implement scopes (active, students, sponsor, completed, waiting, in_progress)
|
|
- [ ] Subtask 4.5: Implement instance methods (complete!, mark_in_progress!, waiting?, completed?)
|
|
- [ ] Subtask 4.6: Include SoftDeletable module
|
|
- [ ] Subtask 4.7: Write model spec for CohortEnrollment
|
|
|
|
- [ ] Task 5: Verify integration with existing tables (AC: IV1, IV2)
|
|
- [ ] Subtask 5.1: Verify Cohort can reference Template model
|
|
- [ ] Subtask 5.2: Verify CohortEnrollment can reference Submission model
|
|
- [ ] Subtask 5.3: Verify no conflicts with existing DocuSeal models
|
|
|
|
- [ ] Task 6: Write comprehensive model tests (AC: Quality 3, 4)
|
|
- [ ] Subtask 6.1: Write unit tests for all validations
|
|
- [ ] Subtask 6.2: Write unit tests for all associations
|
|
- [ ] Subtask 6.3: Write unit tests for all scopes
|
|
- [ ] Subtask 6.4: Write unit tests for state machine transitions
|
|
- [ ] Subtask 6.5: Write unit tests for instance methods
|
|
- [ ] Subtask 6.6: Write unit tests for FeatureFlag functionality
|
|
- [ ] Subtask 6.7: Achieve >80% test coverage
|
|
|
|
- [ ] Task 7: Verify performance (AC: IV3)
|
|
- [ ] Subtask 7.1: Test N+1 query issues with eager loading
|
|
- [ ] Subtask 7.2: Verify query performance with 1000+ records
|
|
- [ ] Subtask 7.3: Optimize any slow queries
|
|
|
|
- [ ] Task 8: Code quality verification (AC: Quality 1, 2, 5)
|
|
- [ ] Subtask 8.1: Run RuboCop and fix violations
|
|
- [ ] Subtask 8.2: Add YARD comments to all public methods
|
|
- [ ] Subtask 8.3: Verify RuboCop compliance
|
|
|
|
---
|
|
|
|
## Dev Notes
|
|
|
|
### Relevant Source Tree
|
|
|
|
```
|
|
app/models/
|
|
├── feature_flag.rb (new)
|
|
├── institution.rb (new)
|
|
├── cohort.rb (new)
|
|
├── cohort_enrollment.rb (new)
|
|
└── concerns/
|
|
└── soft_deletable.rb (existing)
|
|
└── feature_flag_check.rb (new)
|
|
|
|
app/controllers/concerns/
|
|
└── feature_flag_check.rb (new)
|
|
|
|
db/migrate/
|
|
└── 20260116000001_create_feature_flags.rb (new)
|
|
|
|
spec/models/
|
|
├── feature_flag_spec.rb (new)
|
|
├── institution_spec.rb (new)
|
|
├── cohort_spec.rb (new)
|
|
└── cohort_enrollment_spec.rb (new)
|
|
|
|
docs/architecture/
|
|
├── data-models.md (source for schema)
|
|
├── coding-standards.md (source for conventions)
|
|
└── testing-strategy.md (source for test patterns)
|
|
```
|
|
|
|
### Database Schema (from docs/architecture/data-models.md)
|
|
|
|
**Table: institutions**
|
|
```ruby
|
|
create_table :institutions do |t|
|
|
t.string :name, null: false
|
|
t.string :email, null: false
|
|
t.string :contact_person
|
|
t.string :phone
|
|
t.jsonb :settings, default: {}
|
|
t.timestamps
|
|
t.datetime :deleted_at
|
|
end
|
|
```
|
|
|
|
**Table: cohorts**
|
|
```ruby
|
|
create_table :cohorts do |t|
|
|
t.references :institution, null: false, foreign_key: true
|
|
t.references :template, null: false
|
|
t.string :name, null: false
|
|
t.string :program_type, null: false # learnership/internship/candidacy
|
|
t.string :sponsor_email, null: false
|
|
t.jsonb :required_student_uploads, default: []
|
|
t.jsonb :cohort_metadata, default: {}
|
|
t.string :status, default: 'draft'
|
|
t.datetime :tp_signed_at
|
|
t.datetime :students_completed_at
|
|
t.datetime :sponsor_completed_at
|
|
t.datetime :finalized_at
|
|
t.timestamps
|
|
t.datetime :deleted_at
|
|
end
|
|
```
|
|
|
|
**Table: cohort_enrollments**
|
|
```ruby
|
|
create_table :cohort_enrollments do |t|
|
|
t.references :cohort, null: false, foreign_key: true
|
|
t.references :submission, null: false
|
|
t.string :student_email, null: false
|
|
t.string :student_name
|
|
t.string :student_surname
|
|
t.string :student_id
|
|
t.string :status, default: 'waiting'
|
|
t.string :role, default: 'student'
|
|
t.jsonb :uploaded_documents, default: {}
|
|
t.jsonb :values, default: {}
|
|
t.datetime :completed_at
|
|
t.timestamps
|
|
t.datetime :deleted_at
|
|
end
|
|
```
|
|
|
|
### Coding Standards (from docs/architecture/coding-standards.md)
|
|
|
|
**Model Conventions:**
|
|
- All models inherit from `ApplicationRecord`
|
|
- Use `include SoftDeletable` for soft delete functionality
|
|
- Use `strip_attributes` for data cleaning
|
|
- Associations must be explicit with class names when needed
|
|
- Validations should be specific and ordered
|
|
- Scopes must use lambdas
|
|
- Callbacks should be in private methods
|
|
|
|
**File Naming:**
|
|
- `app/models/institution.rb` (not Institution.rb)
|
|
- `app/models/cohort.rb` (not cohort_model.rb)
|
|
- `app/models/cohort_enrollment.rb`
|
|
|
|
**Association Patterns:**
|
|
```ruby
|
|
class Cohort < ApplicationRecord
|
|
belongs_to :institution
|
|
belongs_to :template # Existing DocuSeal model
|
|
has_many :cohort_enrollments, dependent: :destroy
|
|
has_many :submissions, through: :cohort_enrollments
|
|
end
|
|
```
|
|
|
|
### Testing Standards (from docs/architecture/testing-strategy.md)
|
|
|
|
**Model Test Coverage:**
|
|
- Validations (presence, format, inclusion)
|
|
- Associations (belongs_to, has_many, through)
|
|
- Scopes (active, completed, etc.)
|
|
- Callbacks (before_create, after_commit)
|
|
- Instance methods
|
|
- Class methods
|
|
- State machine transitions (for Cohort)
|
|
|
|
**Test Pyramid:**
|
|
- Unit tests (60-70%): Model specs in `spec/models/`
|
|
- Integration tests (20-30%): Request specs in `spec/requests/`
|
|
- E2E tests (5-10%): System specs in `spec/system/`
|
|
|
|
**Coverage Target:** 80% minimum, 90% for critical paths
|
|
|
|
### Feature Flag System (from PRD)
|
|
|
|
**Purpose:** Enable/disable FloDoc functionality without code changes
|
|
|
|
**Implementation:**
|
|
```ruby
|
|
# app/models/feature_flag.rb
|
|
class FeatureFlag < ApplicationRecord
|
|
validates :name, uniqueness: true
|
|
|
|
def self.enabled?(feature_name)
|
|
flag = find_by(name: feature_name)
|
|
flag&.enabled || false
|
|
end
|
|
|
|
def self.enable!(feature_name)
|
|
find_or_create_by(name: feature_name).update(enabled: true)
|
|
end
|
|
|
|
def self.disable!(feature_name)
|
|
find_or_create_by(name: feature_name).update(enabled: false)
|
|
end
|
|
end
|
|
```
|
|
|
|
**Default Flags:**
|
|
- `flodoc_cohorts`: 3-portal cohort management
|
|
- `flodoc_portals`: Student/Sponsor portals
|
|
|
|
**Usage in Controllers:**
|
|
```ruby
|
|
class Flodoc::CohortsController < ApplicationController
|
|
before_action :require_feature(:flodoc_cohorts)
|
|
# ...
|
|
end
|
|
```
|
|
|
|
### State Machine (from docs/architecture/data-models.md)
|
|
|
|
**Cohort States (3 states - Basic Version):**
|
|
1. `draft` - Initial state, being configured by TP
|
|
2. `active` - TP has signed, students can enroll
|
|
3. `completed` - All phases done
|
|
|
|
**Workflow Diagram (from data-models.md):**
|
|
```
|
|
draft → active → [students_enroll] → [students_complete] → [tp_verifies] → [sponsor_signs] → [tp_finalizes] → completed
|
|
```
|
|
|
|
**Note:** This is the **basic version** for Story 1.2. The enhanced 7-state machine (draft, tp_signing, student_enrollment, ready_for_sponsor, sponsor_review, tp_review, completed) is implemented in Story 2.2 (TP Signing Phase Logic) as specified in PRD epic details section 6.2.
|
|
|
|
### Technical Constraints (from docs/architecture/tech-stack.md)
|
|
|
|
**Rails:**
|
|
- Version 7.x
|
|
- ApplicationRecord as base class
|
|
- Use `t.references` for foreign keys in migrations
|
|
|
|
**Database:**
|
|
- PostgreSQL/MySQL/SQLite via DATABASE_URL
|
|
- JSONB fields for flexibility
|
|
- Foreign key constraints required
|
|
|
|
**Integration:**
|
|
- Must not modify existing DocuSeal models
|
|
- Must reference existing `templates` and `submissions` tables
|
|
- Must maintain backward compatibility
|
|
|
|
### Previous Story Insights
|
|
|
|
**From Story 1.1 (Database Schema Extension):**
|
|
- Migration `20260114000001_create_flo_doc_tables.rb` already created
|
|
- Tables `institutions`, `cohorts`, `cohort_enrollments` exist in database
|
|
- All indexes and foreign keys created successfully
|
|
- Integration with existing DocuSeal tables verified (100% test pass rate)
|
|
- Performance requirements met (28.16ms < 120ms NFR1)
|
|
- Test pass rate: 84.8% (>80% requirement met)
|
|
|
|
**Key Learnings:**
|
|
- Use `t.references` in migrations to avoid duplicate indexes/foreign keys
|
|
- Test isolation is critical - rollback migration before running tests
|
|
- Use ActiveRecord models (not raw SQL) for data integrity tests
|
|
- Add timestamps to all test data for NOT NULL constraints
|
|
- Create test helpers for foreign key dependencies
|
|
|
|
### File Locations
|
|
|
|
**New Files to Create:**
|
|
- `app/models/feature_flag.rb`
|
|
- `app/models/institution.rb`
|
|
- `app/models/cohort.rb`
|
|
- `app/models/cohort_enrollment.rb`
|
|
- `app/controllers/concerns/feature_flag_check.rb`
|
|
- `db/migrate/20260116000001_create_feature_flags.rb`
|
|
- `spec/models/feature_flag_spec.rb`
|
|
- `spec/models/institution_spec.rb`
|
|
- `spec/models/cohort_spec.rb`
|
|
- `spec/models/cohort_enrollment_spec.rb`
|
|
|
|
**Existing Files to Reference:**
|
|
- `app/models/application_record.rb` (base class)
|
|
- `app/models/concerns/soft_deletable.rb` (existing concern)
|
|
- `app/models/template.rb` (existing DocuSeal model)
|
|
- `app/models/submission.rb` (existing DocuSeal model)
|
|
|
|
### Testing
|
|
|
|
**Migration Specs:**
|
|
- Location: `spec/migrations/` (not needed for this story - no new tables)
|
|
- Framework: RSpec with `type: :migration`
|
|
|
|
**Model Specs:**
|
|
- Location: `spec/models/`
|
|
- Framework: RSpec with `type: :model`
|
|
- Coverage: Validations, associations, scopes, callbacks, instance methods
|
|
|
|
**Integration Specs:**
|
|
- Location: `spec/integration/` or `spec/requests/`
|
|
- Framework: RSpec with `type: :request`
|
|
- Coverage: API endpoints, controller actions, model interactions
|
|
|
|
**Key Test Requirements:**
|
|
- All validations must be tested
|
|
- All associations must be tested with shoulda-matchers
|
|
- All scopes must be tested with sample data
|
|
- State machine transitions must be tested
|
|
- Feature flag methods must be tested
|
|
- Integration with existing models must be verified
|
|
- Test coverage must exceed 80%
|
|
|
|
### Technical Constraints (from docs/architecture/tech-stack.md)
|
|
|
|
**Database:**
|
|
- PostgreSQL/MySQL/SQLite via DATABASE_URL
|
|
- JSONB fields for flexibility
|
|
- Foreign key constraints required
|
|
|
|
**Rails:**
|
|
- Version 7.x
|
|
- ApplicationRecord as base class
|
|
- Use `t.references` for foreign keys in migrations
|
|
|
|
**Integration:**
|
|
- Must not modify existing DocuSeal models
|
|
- Must reference existing `templates` and `submissions` tables
|
|
- Must maintain backward compatibility
|
|
|
|
### Testing Standards (from docs/architecture/testing-strategy.md)
|
|
|
|
**Model Tests (Unit):**
|
|
- Location: `spec/models/`
|
|
- Coverage: Validations, associations, scopes, callbacks, instance methods
|
|
- Framework: RSpec with shoulda-matchers
|
|
|
|
**Integration Tests:**
|
|
- Location: `spec/requests/api/v1/`
|
|
- Coverage: API endpoints, authentication, authorization
|
|
- Framework: RSpec with `type: :request`
|
|
|
|
**Test Coverage Target:** 80% minimum, 90% for critical paths
|
|
|
|
### File Locations
|
|
|
|
**New Files to Create:**
|
|
- `app/models/feature_flag.rb`
|
|
- `app/models/institution.rb`
|
|
- `app/models/cohort.rb`
|
|
- `app/models/cohort_enrollment.rb`
|
|
- `app/controllers/concerns/feature_flag_check.rb`
|
|
- `db/migrate/20260116000001_create_feature_flags.rb`
|
|
- `spec/models/feature_flag_spec.rb`
|
|
- `spec/models/institution_spec.rb`
|
|
- `spec/models/cohort_spec.rb`
|
|
- `spec/models/cohort_enrollment_spec.rb`
|
|
|
|
**Existing Files to Reference:**
|
|
- `app/models/application_record.rb` (base class)
|
|
- `app/models/concerns/soft_deletable.rb` (existing concern)
|
|
- `app/models/template.rb` (existing DocuSeal model)
|
|
- `app/models/submission.rb` (existing DocuSeal model)
|
|
|
|
---
|
|
|
|
## Testing
|
|
|
|
### Model Testing Strategy
|
|
|
|
**Validation Tests:**
|
|
```ruby
|
|
# spec/models/cohort_spec.rb
|
|
describe 'validations' do
|
|
it { should validate_presence_of(:name) }
|
|
it { should validate_presence_of(:program_type) }
|
|
it { should validate_inclusion_of(:status).in_array(%w[draft active completed]) }
|
|
|
|
it 'validates sponsor email format' do
|
|
cohort = build(:cohort, sponsor_email: 'invalid')
|
|
expect(cohort).not_to be_valid
|
|
expect(cohort.errors[:sponsor_email]).to include('must be a valid email')
|
|
end
|
|
end
|
|
```
|
|
|
|
**Association Tests:**
|
|
```ruby
|
|
describe 'associations' do
|
|
it { should belong_to(:institution) }
|
|
it { should belong_to(:template) }
|
|
it { should have_many(:cohort_enrollments).dependent(:destroy) }
|
|
it { should have_many(:submissions).through(:cohort_enrollments) }
|
|
end
|
|
```
|
|
|
|
**Scope Tests:**
|
|
```ruby
|
|
describe 'scopes' do
|
|
let!(:active_cohort) { create(:cohort, status: 'active') }
|
|
let!(:draft_cohort) { create(:cohort, status: 'draft') }
|
|
|
|
it '.active returns only active cohorts' do
|
|
expect(Cohort.active).to include(active_cohort)
|
|
expect(Cohort.active).not_to include(draft_cohort)
|
|
end
|
|
end
|
|
```
|
|
|
|
**State Machine Tests:**
|
|
```ruby
|
|
describe 'state machine' do
|
|
let(:cohort) { create(:cohort, status: 'draft') }
|
|
|
|
it 'transitions from draft to tp_signing' do
|
|
expect { cohort.start_tp_signing! }.to change(cohort, :status).from('draft').to('tp_signing')
|
|
end
|
|
|
|
it 'transitions from tp_signing to student_enrollment' do
|
|
cohort.update!(status: 'tp_signing')
|
|
expect { cohort.complete_tp_signing! }.to change(cohort, :status).from('tp_signing').to('student_enrollment')
|
|
end
|
|
end
|
|
```
|
|
|
|
### Integration Testing Strategy
|
|
|
|
**API Request Specs:**
|
|
```ruby
|
|
# spec/requests/api/v1/cohorts_spec.rb
|
|
describe 'POST /api/v1/cohorts' do
|
|
it 'creates a cohort' do
|
|
expect {
|
|
post '/api/v1/cohorts', headers: headers, params: valid_params
|
|
}.to change(Cohort, :count).by(1)
|
|
|
|
expect(response).to have_http_status(:created)
|
|
expect(json_response['name']).to eq('Test Cohort')
|
|
end
|
|
end
|
|
```
|
|
|
|
### Test Coverage Requirements
|
|
|
|
**Minimum Coverage:** 80%
|
|
**Critical Paths Coverage:** 90%
|
|
|
|
**Coverage Areas:**
|
|
- Model validations (100%)
|
|
- Model associations (100%)
|
|
- Model scopes (100%)
|
|
- Model instance methods (90%)
|
|
- Model class methods (90%)
|
|
- State machine transitions (100%)
|
|
- Feature flag methods (100%)
|
|
- API endpoints (90%)
|
|
|
|
---
|
|
|
|
## Acceptance Criteria
|
|
|
|
### Functional
|
|
1. ✅ All three models created with correct class structure
|
|
2. ✅ All associations defined correctly
|
|
3. ✅ All validations implemented
|
|
4. ✅ All scopes defined
|
|
5. ✅ State machine logic correct (if used)
|
|
6. ✅ Model methods work as specified
|
|
7. ✅ FeatureFlag model created with enabled?, enable!, disable! methods
|
|
8. ✅ FeatureFlagCheck concern implemented
|
|
9. ✅ Default flags seeded (flodoc_cohorts, flodoc_portals)
|
|
10. ✅ All FloDoc routes protected by feature flags
|
|
|
|
### Integration
|
|
1. ✅ IV1: Models don't break existing DocuSeal models
|
|
2. ✅ IV2: Associations work with existing tables (templates, submissions)
|
|
3. ✅ IV3: Query performance acceptable with 1000+ records
|
|
4. ✅ Feature flags integrate with existing authentication
|
|
|
|
### Security
|
|
1. ✅ No mass assignment vulnerabilities
|
|
2. ✅ Proper attribute whitelisting
|
|
3. ✅ Email validation on all email fields
|
|
4. ✅ Feature flags can disable FloDoc instantly
|
|
|
|
### Quality
|
|
1. ✅ Follow existing code style (RuboCop compliant)
|
|
2. ✅ All methods have YARD comments
|
|
3. ✅ Test coverage > 80%
|
|
4. ✅ No N+1 query issues
|
|
5. ✅ Feature flag tests included
|
|
|
|
---
|
|
|
|
## Change Log
|
|
|
|
| Date | Version | Description | Author |
|
|
|------|---------|-------------|--------|
|
|
| 2026-01-16 | 1.0 | Initial story creation | SM Agent |
|
|
| 2026-01-16 | 1.1 | **CORRECTED:** State machine updated from 7-state to 3-state (basic version) per PRD clarification. Story 1.2 implements basic version (draft, active, completed). Enhanced 7-state machine will be in Story 2.2. | SM Agent |
|
|
|
|
---
|
|
|
|
## Dev Agent Record
|
|
|
|
### Agent Model Used
|
|
James (Full Stack Developer)
|
|
|
|
### Debug Log References
|
|
- [To be populated by development agent]
|
|
|
|
### Completion Notes List
|
|
- [To be populated by development agent]
|
|
|
|
### File List
|
|
- [To be populated by development agent]
|
|
|
|
### Change Log
|
|
| Date | Action | Author |
|
|
|------|--------|--------|
|
|
| [To be populated by development agent] |
|
|
|
|
---
|
|
|
|
## QA Results
|
|
|
|
### 🧪 QA Review: Story 1.2 - Core Models Implementation
|
|
|
|
**Assessment Date:** 2026-01-16
|
|
**QA Agent:** Quinn (Test Architect & Quality Advisor)
|
|
**Overall Status:** ⚠️ **CONCERNS** - Implementation requires careful attention to critical risks
|
|
|
|
---
|
|
|
|
### 📊 Risk Assessment Summary
|
|
|
|
**Risk Score:** 42/100 (Lower is better - 100 = no risk)
|
|
|
|
**Risk Distribution:**
|
|
- **Critical (Score 9):** 0 risks
|
|
- **High (Score 6):** 5 risks ⚠️
|
|
- **Medium (Score 4):** 2 risks
|
|
- **Low (Score 2-3):** 4 risks
|
|
- **Minimal (Score 1):** 1 risk
|
|
|
|
**Top 5 Critical Risks Requiring Immediate Attention:**
|
|
|
|
1. **TECH-001: State Machine Complexity** (Score: 6)
|
|
- **3-state machine** (draft, active, completed) for Story 1.2
|
|
- **7-state machine** (draft, tp_signing, student_enrollment, ready_for_sponsor, sponsor_review, tp_review, completed) for Story 2.2
|
|
- Risk: Incorrect workflow could block business operations
|
|
- **Mitigation:** Comprehensive state transition tests required
|
|
|
|
2. **SEC-001: Feature Flag Bypass** (Score: 6)
|
|
- FloDoc routes may not be properly protected
|
|
- Risk: Premature exposure of functionality
|
|
- **Mitigation:** FeatureFlagCheck concern with controller specs
|
|
|
|
3. **PERF-001: N+1 Query Issues** (Score: 6)
|
|
- Nested associations (institution→cohorts→enrollments)
|
|
- Risk: Performance degradation with 1000+ records
|
|
- **Mitigation:** Eager loading with includes() required
|
|
|
|
4. **DATA-001: Foreign Key Constraint Violations** (Score: 6)
|
|
- References to existing DocuSeal tables
|
|
- Risk: Data integrity issues, failed saves
|
|
- **Mitigation:** FK validation and integration tests
|
|
|
|
5. **BUS-001: State Machine Logic Mismatch** (Score: 6)
|
|
- **RESOLVED:** Story 1.2 implements 3-state basic version (draft, active, completed)
|
|
- Story 2.2 will implement 7-state enhanced version
|
|
- Implementation matches PRD requirements
|
|
- Risk: Workflow doesn't match business needs
|
|
- **Mitigation:** Business requirement validation tests
|
|
|
|
**Risk Assessment File:** `docs/qa/assessments/1.2.core-models-implementation-risk-20260115.md`
|
|
|
|
---
|
|
|
|
### 🎯 Test Design Summary
|
|
|
|
**Total Test Scenarios:** 125 tests across 11 test files
|
|
**Coverage Target:** >80% overall, >90% critical paths
|
|
**Test Pyramid:** 69% unit, 14% integration, 5% performance, 8% security, 6% acceptance
|
|
|
|
**Critical Test Categories:**
|
|
|
|
#### 1. Model Unit Tests (86 tests)
|
|
- **FeatureFlag:** 12 tests (100% coverage)
|
|
- Validations, class methods, instance methods
|
|
- `enabled?`, `enable!`, `disable!` functionality
|
|
|
|
- **Institution:** 15 tests (100% coverage)
|
|
- Validations, associations, scopes
|
|
- Single-record pattern with `.current` method
|
|
- Soft delete behavior
|
|
|
|
- **Cohort:** 35 tests (100% coverage) ⚠️ **MOST CRITICAL**
|
|
- All 7 state transitions (draft → completed)
|
|
- Guard clauses and invalid transitions
|
|
- State machine events and callbacks
|
|
- Association integrity
|
|
|
|
- **CohortEnrollment:** 20 tests (100% coverage)
|
|
- Validations including unique submission_id
|
|
- Status tracking scopes
|
|
- Instance methods for status updates
|
|
|
|
#### 2. Integration Tests (18 tests)
|
|
- **Model Integration:** 12 tests
|
|
- Foreign key constraints with existing tables
|
|
- Association integrity (templates, submissions)
|
|
- Cascading delete behavior
|
|
|
|
- **Feature Flag Integration:** 4 tests
|
|
- Controller protection with enabled/disabled flags
|
|
- Request-level access control
|
|
|
|
#### 3. Performance Tests (6 tests)
|
|
- **N+1 Query Detection:** 3 tests
|
|
- Eager loading verification
|
|
- Query limits with 1000+ records
|
|
- EXPLAIN query analysis
|
|
|
|
- **Query Performance:** 3 tests
|
|
- <120ms requirement verification
|
|
- Large dataset performance
|
|
|
|
#### 4. Security Tests (10 tests)
|
|
- **Mass Assignment Protection:** 2 tests
|
|
- **Email Validation:** 8 tests (all email fields)
|
|
|
|
#### 5. Acceptance Tests (7 tests)
|
|
- **Functional:** 5 tests
|
|
- **Integration:** 2 tests
|
|
|
|
**Test Design File:** `docs/qa/assessments/1.2.core-models-implementation-test-design-20260116.md`
|
|
|
|
---
|
|
|
|
### 🎯 Quality Gate Decision
|
|
|
|
**Gate Status:** ⚠️ **CONCERNS**
|
|
|
|
**Rationale:**
|
|
- ✅ **Test Design:** Comprehensive 125-test design created
|
|
- ✅ **Risk Coverage:** All 12 risks have corresponding test strategies
|
|
- ⚠️ **Implementation:** Not yet completed - cannot verify actual coverage
|
|
- ⚠️ **State Machine:** Complex 7-state machine requires rigorous testing
|
|
- ⚠️ **Feature Flags:** Protection mechanism needs verification
|
|
- ⚠️ **Integration:** Foreign key constraints with existing tables need testing
|
|
|
|
**Score:** 7/10 (Pending implementation verification)
|
|
|
|
---
|
|
|
|
### 📋 Required Actions Before Production
|
|
|
|
#### **MUST FIX (Before Implementation):**
|
|
|
|
1. **State Machine Tests** (Priority 1)
|
|
- Implement all 35 Cohort model tests
|
|
- Test all 7 states and 6 transitions
|
|
- Verify guard clauses prevent invalid transitions
|
|
- Test concurrent state changes
|
|
|
|
2. **Feature Flag Protection** (Priority 1)
|
|
- Implement FeatureFlagCheck concern
|
|
- Add controller specs for all FloDoc routes
|
|
- Test both enabled/disabled states
|
|
- Verify 404/403 responses when disabled
|
|
|
|
3. **Foreign Key Integration Tests** (Priority 1)
|
|
- Test with real template/submission records
|
|
- Verify FK constraints prevent orphaned records
|
|
- Test rollback scenarios
|
|
|
|
4. **N+1 Query Prevention** (Priority 1)
|
|
- Implement eager loading in all queries
|
|
- Add performance tests with 1000+ records
|
|
- Use Bullet gem for detection
|
|
|
|
5. **Test Coverage Verification** (Priority 1)
|
|
- Achieve >80% overall coverage
|
|
- >90% for critical paths (state machine, feature flags)
|
|
- Run full test suite before deployment
|
|
|
|
#### **MONITOR (Post-Implementation):**
|
|
|
|
6. **Performance Monitoring**
|
|
- Query times with 1000+ records
|
|
- State machine transition performance
|
|
- Feature flag toggle impact
|
|
|
|
7. **Data Integrity**
|
|
- Foreign key constraint violations
|
|
- Unique constraint violations
|
|
- JSONB field validation
|
|
|
|
---
|
|
|
|
### 🚨 Risk Mitigation Status
|
|
|
|
| Risk ID | Risk Description | Mitigation Status | Test Coverage |
|
|
|---------|-----------------|-------------------|---------------|
|
|
| TECH-001 | State machine complexity | ⚠️ Pending | 100% designed |
|
|
| TECH-002 | AASM gem integration | ⚠️ Pending | 100% designed |
|
|
| SEC-001 | Feature flag bypass | ⚠️ Pending | 100% designed |
|
|
| SEC-002 | Email validation gaps | ⚠️ Pending | 100% designed |
|
|
| PERF-001 | N+1 query issues | ⚠️ Pending | 100% designed |
|
|
| PERF-002 | Missing indexes | ⚠️ Pending | 100% designed |
|
|
| DATA-001 | Foreign key violations | ⚠️ Pending | 100% designed |
|
|
| DATA-002 | JSONB validation | ⚠️ Pending | 100% designed |
|
|
| DATA-003 | Unique constraint | ⚠️ Pending | 100% designed |
|
|
| BUS-001 | State machine logic | ⚠️ Pending | 100% designed |
|
|
| OPS-001 | Feature flag seeds | ⚠️ Pending | 100% designed |
|
|
| OPS-002 | Test coverage <80% | ⚠️ Pending | 100% designed |
|
|
|
|
**Overall Mitigation:** 0% (All risks designed but not yet implemented/tested)
|
|
|
|
---
|
|
|
|
### 📊 Acceptance Criteria Status
|
|
|
|
#### Functional
|
|
1. ⚠️ All three models created with correct class structure
|
|
2. ⚠️ All associations defined correctly
|
|
3. ⚠️ All validations implemented
|
|
4. ⚠️ All scopes defined
|
|
5. ⚠️ State machine logic correct (if used)
|
|
6. ⚠️ Model methods work as specified
|
|
7. ⚠️ FeatureFlag model created with enabled?, enable!, disable! methods
|
|
8. ⚠️ FeatureFlagCheck concern implemented
|
|
9. ⚠️ Default flags seeded (flodoc_cohorts, flodoc_portals)
|
|
10. ⚠️ All FloDoc routes protected by feature flags
|
|
|
|
#### Integration
|
|
1. ⚠️ IV1: Models don't break existing DocuSeal models
|
|
2. ⚠️ IV2: Associations work with existing tables (templates, submissions)
|
|
3. ⚠️ IV3: Query performance acceptable with 1000+ records
|
|
4. ⚠️ Feature flags integrate with existing authentication
|
|
|
|
#### Security
|
|
1. ⚠️ No mass assignment vulnerabilities
|
|
2. ⚠️ Proper attribute whitelisting
|
|
3. ⚠️ Email validation on all email fields
|
|
4. ⚠️ Feature flags can disable FloDoc instantly
|
|
|
|
#### Quality
|
|
1. ⚠️ Follow existing code style (RuboCop compliant)
|
|
2. ⚠️ All methods have YARD comments
|
|
3. ⚠️ Test coverage > 80%
|
|
4. ⚠️ No N+1 query issues
|
|
5. ⚠️ Feature flag tests included
|
|
|
|
**Overall AC Completion:** 0% (All pending implementation)
|
|
|
|
---
|
|
|
|
### 🎯 Final Recommendation
|
|
|
|
**⚠️ DO NOT PROCEED TO PRODUCTION YET**
|
|
|
|
**Current Status:** Story 1.2 is in Draft status with comprehensive test design created but implementation not started.
|
|
|
|
**Required Sequence:**
|
|
1. **Review Test Design** - Validate 125 test scenarios match requirements
|
|
2. **Implement Models** - Create 4 models with all specified functionality
|
|
3. **Implement Tests** - Write all 125 test scenarios
|
|
4. **Verify Coverage** - Achieve >80% coverage, >90% critical paths
|
|
5. **Run Full Suite** - Pass all tests with no failures
|
|
6. **Performance Test** - Verify <120ms query times
|
|
7. **Security Audit** - Verify all security requirements met
|
|
8. **QA Review** - Re-run comprehensive review after implementation
|
|
|
|
**Risk Level:** HIGH - Complex state machine and feature flag protection require rigorous testing
|
|
|
|
**Next Steps:**
|
|
1. Developer implements models following test design specifications
|
|
2. Developer writes tests using the 125 test scenarios provided
|
|
3. Developer achieves >80% test coverage
|
|
4. Developer runs full test suite and fixes any failures
|
|
5. Developer requests QA review after implementation complete
|
|
6. QA Agent performs comprehensive review with actual implementation
|
|
|
|
**Estimated Effort:**
|
|
- Model implementation: 4-6 hours
|
|
- Test implementation: 6-8 hours
|
|
- Coverage verification: 1-2 hours
|
|
- QA review: 1-2 hours
|
|
- **Total:** 12-18 hours
|
|
|
|
---
|
|
|
|
### 📁 Files Created by QA Agent
|
|
|
|
**Risk Assessment:**
|
|
- `docs/qa/assessments/1.2.core-models-implementation-risk-20260115.md`
|
|
|
|
**Test Design:**
|
|
- `docs/qa/assessments/1.2.core-models-implementation-test-design-20260116.md`
|
|
|
|
**Gate YAML Block (Ready for Integration):**
|
|
```yaml
|
|
risk_summary:
|
|
totals:
|
|
critical: 0
|
|
high: 5
|
|
medium: 2
|
|
low: 4
|
|
minimal: 1
|
|
highest:
|
|
id: TECH-001
|
|
score: 6
|
|
title: 'State machine complexity - 7 states with complex transitions'
|
|
|
|
test_design:
|
|
totals:
|
|
unit_tests: 86
|
|
integration_tests: 18
|
|
performance_tests: 6
|
|
security_tests: 10
|
|
acceptance_tests: 7
|
|
total: 125
|
|
coverage_targets:
|
|
overall: >80%
|
|
critical_paths: >90%
|
|
critical_tests:
|
|
- 'State machine transitions (7 states, all events)'
|
|
- 'Feature flag protection (controller/request level)'
|
|
- 'Foreign key constraints (integration with existing tables)'
|
|
- 'N+1 query detection (performance with 1000+ records)'
|
|
- 'Email validation (all email fields)'
|
|
```
|
|
|
|
---
|
|
|
|
### 🚨 Quality Gate Blockers
|
|
|
|
| Blocker | Severity | Impact | Status |
|
|
|---------|----------|--------|--------|
|
|
| Implementation Not Started | CRITICAL | Cannot verify actual functionality | ⚠️ BLOCKING |
|
|
| Tests Not Written | CRITICAL | Cannot verify coverage | ⚠️ BLOCKING |
|
|
| State Machine Not Tested | HIGH | Complex 7-state machine unverified | ⚠️ BLOCKING |
|
|
| Feature Flag Protection Not Verified | HIGH | Security risk | ⚠️ BLOCKING |
|
|
| Performance Not Measured | MEDIUM | Cannot verify <120ms requirement | ⚠️ BLOCKING |
|
|
|
|
**Status:** ⚠️ **BLOCKED** - All blockers must be resolved before production deployment
|
|
|
|
---
|
|
|
|
**Story Status:** Ready for development implementation
|
|
**QA Status:** Test design complete, awaiting implementation
|
|
**Recommendation:** Proceed with implementation following provided test design
|