# 4. Technical Constraints and Integration Requirements ## 4.1 Existing Technology Stack **Based on Architecture Analysis** (docs/current-app-sitemap.md): **Languages:** - Ruby 3.4.2 - JavaScript (Vue.js 3) - HTML/CSS (TailwindCSS 3.4.17) **Frameworks:** - Ruby on Rails 7.x (with Shakapacker 8.0) - Vue.js 3 with Composition API - Devise for authentication - Cancancan for authorization - Sidekiq for background processing **Database:** - PostgreSQL/MySQL/SQLite (configured via DATABASE_URL) - Redis for Sidekiq job queue **Infrastructure:** - Puma web server - Active Storage (S3, Google Cloud, Azure, or local disk) - SMTP server for email delivery **External Dependencies:** - HexaPDF (PDF generation and signing) - PDFium (PDF rendering) - rubyXL (Excel export - **to be added**) - Ngrok (for local testing with public URLs) **Key Libraries & Gems:** - `devise` - Authentication - `devise-two-factor` - 2FA support - `cancancan` - Authorization - `sidekiq` - Background jobs - `hexapdf` - PDF processing - `prawn` - PDF generation (alternative) - `rubyXL` - Excel file generation (**required for FR23**) ## 4.2 Integration Approach **Database Integration Strategy:** - **New Tables Only**: Create `cohorts`, `cohort_enrollments`, `institutions`, `sponsors` tables - **Foreign Keys**: Link to existing `templates`, `submissions`, `users` tables - **No Schema Modifications**: Existing DocuSeal tables remain unchanged - **Migration Safety**: All migrations must be reversible - **Data Isolation**: Use `institution_id` scoping for all FloDoc queries **API Integration Strategy:** - **Namespace Extension**: Add `/api/v1/flodoc/` namespace for new endpoints - **Pattern Consistency**: Follow existing DocuSeal REST conventions - **Authentication**: Reuse existing Devise + JWT infrastructure - **Rate Limiting**: Apply existing rate limits to new endpoints - **Webhook Compatibility**: New cohort events trigger existing webhook infrastructure **Frontend Integration Strategy:** - **Vue.js Architecture**: Extend existing Vue 3 app with new portal components - **Design System**: Replace DaisyUI with custom TailwindCSS (per CR3) - **Component Structure**: Create new portal-specific components in `app/javascript/cohorts/` - **Routing**: Use existing Vue Router with new portal routes - **State Management**: Vuex or Pinia for cohort state (to be determined) - **No Breaking Changes**: Existing DocuSeal UI remains functional **Testing Integration Strategy:** - **RSpec**: Extend existing test suite with new model/request specs - **System Tests**: Add Capybara tests for 3-portal workflows - **Vue Test Utils**: Component tests for new portal interfaces - **FactoryBot**: Create factories for new models - **Existing Tests**: All DocuSeal tests must continue passing ## 4.3 Code Organization and Standards **File Structure Approach:** ``` app/ ├── models/ │ ├── cohort.rb # New: Cohort management │ ├── cohort_enrollment.rb # New: Student enrollment tracking │ ├── institution.rb # New: Single institution model │ ├── sponsor.rb # New: Ad-hoc sponsor model │ └── concerns/ │ └── user_flo_doc_additions.rb # New: User model extension │ ├── controllers/ │ ├── api/ │ │ └── v1/ │ │ ├── flodoc/ │ │ │ ├── cohorts_controller.rb │ │ │ ├── enrollments_controller.rb │ │ │ └── excel_export_controller.rb │ │ └── admin/ │ │ ├── invitations_controller.rb │ │ └── security_events_controller.rb │ └── cohorts/ │ └── admin_controller.rb # Web interface │ ├── services/ │ ├── invitation_service.rb # Admin invitation logic │ ├── cohort_service.rb # Cohort lifecycle management │ ├── sponsor_service.rb # Sponsor access management │ └── excel_export_service.rb # Excel generation (FR23) │ ├── jobs/ │ ├── cohort_admin_invitation_job.rb │ ├── sponsor_access_job.rb │ └── excel_export_job.rb │ ├── mailers/ │ └── cohort_mailer.rb # Cohort-specific emails │ └── javascript/ └── cohorts/ ├── portals/ │ ├── tp_portal/ # Admin interface │ ├── student_portal/ # Student interface │ └── sponsor_portal/ # Sponsor interface └── components/ # Shared Vue components ``` **Naming Conventions:** - **Models**: `Cohort`, `CohortEnrollment`, `Institution`, `Sponsor` (PascalCase, singular) - **Controllers**: `CohortsController`, `Cohorts::AdminController` (namespaced) - **Services**: `CohortService`, `InvitationService` (PascalCase, descriptive) - **Jobs**: `CohortInvitationJob` (PascalCase, ends with Job) - **Vue Components**: `CohortDashboard.vue`, `SponsorPanel.vue` (PascalCase) - **Variables**: `cohort_enrollments` (snake_case, plural for collections) - **Routes**: `/flodoc/cohorts`, `/admin/invitations` (kebab-case in URLs) **Coding Standards:** - **Ruby**: Follow existing RuboCop configuration - **JavaScript**: Follow existing ESLint configuration - **Vue.js**: Use Composition API, `