claude-code-orchestrator-kit 1.4.1 → 1.4.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/business/workers/lead-research-assistant.md +199 -0
- package/.claude/agents/database/workers/api-builder.md +8 -0
- package/.claude/agents/database/workers/database-architect.md +11 -3
- package/.claude/agents/database/workers/supabase-auditor.md +7 -7
- package/.claude/agents/database/workers/supabase-fixer.md +825 -0
- package/.claude/agents/database/workers/supabase-realtime-optimizer.md +1086 -0
- package/.claude/agents/database/workers/supabase-storage-optimizer.md +1187 -0
- package/.claude/agents/development/workers/code-reviewer.md +17 -2
- package/.claude/agents/development/workers/code-structure-refactorer.md +771 -0
- package/.claude/agents/development/workers/judge-specialist.md +3275 -0
- package/.claude/agents/development/workers/langgraph-specialist.md +1343 -0
- package/.claude/agents/development/workers/stage-pipeline-specialist.md +1173 -0
- package/.claude/agents/frontend/workers/fullstack-nextjs-specialist.md +10 -0
- package/.claude/agents/frontend/workers/nextjs-ui-designer.md +30 -0
- package/.claude/agents/health/workers/bug-fixer.md +31 -3
- package/.claude/agents/health/workers/bug-hunter.md +0 -1
- package/.claude/agents/health/workers/dead-code-hunter.md +167 -75
- package/.claude/agents/health/workers/dead-code-remover.md +217 -66
- package/.claude/agents/health/workers/dependency-auditor.md +83 -24
- package/.claude/agents/health/workers/dependency-updater.md +0 -1
- package/.claude/agents/health/workers/security-scanner.md +0 -1
- package/.claude/agents/infrastructure/workers/bullmq-worker-specialist.md +748 -0
- package/.claude/agents/infrastructure/workers/deployment-engineer.md +446 -0
- package/.claude/agents/infrastructure/workers/infrastructure-specialist.md +2 -2
- package/.claude/agents/infrastructure/workers/rag-specialist.md +799 -0
- package/.claude/agents/infrastructure/workers/server-hardening-specialist.md +1128 -0
- package/.claude/agents/integrations/workers/lms-integration-specialist.md +866 -0
- package/.claude/agents/meta/workers/meta-agent-v3.md +22 -0
- package/.claude/agents/testing/workers/integration-tester.md +1 -1
- package/.claude/agents/testing/workers/test-writer.md +16 -0
- package/.claude/commands/health-bugs.md +14 -281
- package/.claude/commands/health-cleanup.md +14 -281
- package/.claude/commands/health-deps.md +14 -281
- package/.claude/commands/health-metrics.md +51 -709
- package/.claude/commands/health-reuse.md +14 -311
- package/.claude/commands/health-security.md +14 -281
- package/.claude/commands/push.md +17 -3
- package/.claude/commands/speckit.implement.md +0 -11
- package/.claude/commands/supabase-performance-optimizer.md +73 -0
- package/.claude/commands/ultra-think.md +158 -0
- package/.claude/commands/worktree.md +150 -0
- package/.claude/scripts/gates/check-bundle-size.sh +0 -0
- package/.claude/scripts/gates/check-coverage.sh +0 -0
- package/.claude/scripts/gates/check-security.sh +0 -0
- package/.claude/scripts/release.sh +469 -94
- package/.claude/skills/algorithmic-art/LICENSE.txt +202 -0
- package/.claude/skills/algorithmic-art/SKILL.md +405 -0
- package/.claude/skills/algorithmic-art/templates/generator_template.js +223 -0
- package/.claude/skills/algorithmic-art/templates/viewer.html +599 -0
- package/.claude/skills/artifacts-builder/LICENSE.txt +202 -0
- package/.claude/skills/artifacts-builder/SKILL.md +74 -0
- package/.claude/skills/artifacts-builder/scripts/bundle-artifact.sh +54 -0
- package/.claude/skills/artifacts-builder/scripts/init-artifact.sh +322 -0
- package/.claude/skills/artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
- package/.claude/skills/bug-health-inline/SKILL.md +221 -0
- package/.claude/skills/bug-health-inline/references/worker-prompts.md +182 -0
- package/.claude/skills/canvas-design/LICENSE.txt +202 -0
- package/.claude/skills/canvas-design/SKILL.md +130 -0
- package/.claude/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +94 -0
- package/.claude/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Jura-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- package/.claude/skills/changelog-generator/SKILL.md +104 -0
- package/.claude/skills/cleanup-health-inline/SKILL.md +224 -0
- package/.claude/skills/code-reviewer/SKILL.md +209 -0
- package/.claude/skills/code-reviewer/references/code_review_checklist.md +103 -0
- package/.claude/skills/code-reviewer/references/coding_standards.md +103 -0
- package/.claude/skills/code-reviewer/references/common_antipatterns.md +103 -0
- package/.claude/skills/code-reviewer/scripts/code_quality_checker.py +114 -0
- package/.claude/skills/code-reviewer/scripts/pr_analyzer.py +114 -0
- package/.claude/skills/code-reviewer/scripts/review_report_generator.py +114 -0
- package/.claude/skills/content-research-writer/SKILL.md +538 -0
- package/.claude/skills/deps-health-inline/SKILL.md +227 -0
- package/.claude/skills/frontend-aesthetics/SKILL.md +51 -396
- package/.claude/skills/git-commit-helper/SKILL.md +203 -0
- package/.claude/skills/lead-research-assistant/SKILL.md +199 -0
- package/.claude/skills/reuse-health-inline/SKILL.md +248 -0
- package/.claude/skills/rollback-changes/SKILL.md +50 -524
- package/.claude/skills/run-quality-gate/SKILL.md +36 -346
- package/.claude/skills/security-health-inline/SKILL.md +224 -0
- package/.claude/skills/senior-architect/SKILL.md +209 -0
- package/.claude/skills/senior-architect/references/architecture_patterns.md +755 -0
- package/.claude/skills/senior-architect/references/system_design_workflows.md +749 -0
- package/.claude/skills/senior-architect/references/tech_decision_guide.md +612 -0
- package/.claude/skills/senior-architect/scripts/architecture_diagram_generator.py +114 -0
- package/.claude/skills/senior-architect/scripts/dependency_analyzer.py +114 -0
- package/.claude/skills/senior-architect/scripts/project_architect.py +114 -0
- package/.claude/skills/senior-devops/SKILL.md +209 -0
- package/.claude/skills/senior-devops/references/cicd_pipeline_guide.md +103 -0
- package/.claude/skills/senior-devops/references/deployment_strategies.md +103 -0
- package/.claude/skills/senior-devops/references/infrastructure_as_code.md +103 -0
- package/.claude/skills/senior-devops/scripts/deployment_manager.py +114 -0
- package/.claude/skills/senior-devops/scripts/pipeline_generator.py +114 -0
- package/.claude/skills/senior-devops/scripts/terraform_scaffolder.py +114 -0
- package/.claude/skills/senior-prompt-engineer/SKILL.md +226 -0
- package/.claude/skills/senior-prompt-engineer/references/agentic_system_design.md +80 -0
- package/.claude/skills/senior-prompt-engineer/references/llm_evaluation_frameworks.md +80 -0
- package/.claude/skills/senior-prompt-engineer/references/prompt_engineering_patterns.md +80 -0
- package/.claude/skills/senior-prompt-engineer/scripts/agent_orchestrator.py +100 -0
- package/.claude/skills/senior-prompt-engineer/scripts/prompt_optimizer.py +100 -0
- package/.claude/skills/senior-prompt-engineer/scripts/rag_evaluator.py +100 -0
- package/.claude/skills/setup-knip/SKILL.md +372 -0
- package/.claude/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/.claude/skills/systematic-debugging/SKILL.md +296 -0
- package/.claude/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/.claude/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/.claude/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/.claude/skills/systematic-debugging/find-polluter.sh +63 -0
- package/.claude/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/.claude/skills/systematic-debugging/test-academic.md +14 -0
- package/.claude/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/.claude/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/.claude/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/.claude/skills/theme-factory/LICENSE.txt +202 -0
- package/.claude/skills/theme-factory/SKILL.md +59 -0
- package/.claude/skills/theme-factory/theme-showcase.pdf +0 -0
- package/.claude/skills/theme-factory/themes/arctic-frost.md +19 -0
- package/.claude/skills/theme-factory/themes/botanical-garden.md +19 -0
- package/.claude/skills/theme-factory/themes/desert-rose.md +19 -0
- package/.claude/skills/theme-factory/themes/forest-canopy.md +19 -0
- package/.claude/skills/theme-factory/themes/golden-hour.md +19 -0
- package/.claude/skills/theme-factory/themes/midnight-galaxy.md +19 -0
- package/.claude/skills/theme-factory/themes/modern-minimalist.md +19 -0
- package/.claude/skills/theme-factory/themes/ocean-depths.md +19 -0
- package/.claude/skills/theme-factory/themes/sunset-boulevard.md +19 -0
- package/.claude/skills/theme-factory/themes/tech-innovation.md +19 -0
- package/.claude/skills/ui-design-system/SKILL.md +32 -0
- package/.claude/skills/ui-design-system/scripts/design_token_generator.py +529 -0
- package/.claude/skills/ux-researcher-designer/SKILL.md +30 -0
- package/.claude/skills/ux-researcher-designer/scripts/persona_generator.py +508 -0
- package/.claude/skills/webapp-testing/LICENSE.txt +202 -0
- package/.claude/skills/webapp-testing/SKILL.md +96 -0
- package/.claude/skills/webapp-testing/examples/console_logging.py +35 -0
- package/.claude/skills/webapp-testing/examples/element_discovery.py +40 -0
- package/.claude/skills/webapp-testing/examples/static_html_automation.py +33 -0
- package/.claude/skills/webapp-testing/scripts/with_server.py +106 -0
- package/.gitignore +4 -0
- package/README.md +492 -1093
- package/README.ru.md +719 -0
- package/docs/Agents Ecosystem/AGENT-ORCHESTRATION.md +2 -2
- package/docs/COMMANDS-GUIDE.md +0 -15
- package/docs/reports/skills/new-skills-analysis-2025-12.md +331 -0
- package/package.json +11 -3
- package/.claude/agents/health/orchestrators/bug-orchestrator.md +0 -1084
- package/.claude/agents/health/orchestrators/dead-code-orchestrator.md +0 -1064
- package/.claude/agents/health/orchestrators/dependency-orchestrator.md +0 -1064
- package/.claude/agents/health/orchestrators/reuse-orchestrator.md +0 -1112
- package/.claude/agents/health/orchestrators/security-orchestrator.md +0 -1064
- package/.claude/commands/worktree-cleanup.md +0 -382
- package/.claude/commands/worktree-create.md +0 -287
- package/.claude/commands/worktree-list.md +0 -239
- package/.claude/commands/worktree-remove.md +0 -339
- package/.claude/project-index.md +0 -75
- package/.claude/skills/load-project-context/SKILL.md +0 -89
- package/.claude/skills/resume-session/SKILL.md +0 -164
- package/.claude/skills/save-session-context/SKILL.md +0 -123
- package/.claude/templates/project-index.template.md +0 -67
- package/.claude/templates/session/context.template.md +0 -40
- package/.claude/templates/session/log.template.md +0 -72
- package/.github/BRANCH_PROTECTION.md +0 -137
- package/.github/workflows/build.yml +0 -70
- package/.github/workflows/deploy-staging.yml +0 -90
- package/.github/workflows/test.yml +0 -104
|
@@ -0,0 +1,749 @@
|
|
|
1
|
+
# System Design Workflows
|
|
2
|
+
|
|
3
|
+
Step-by-step workflows for common system design tasks in the MegaCampusAI monorepo.
|
|
4
|
+
|
|
5
|
+
## Workflow 1: New Feature Development
|
|
6
|
+
|
|
7
|
+
End-to-end workflow for adding a new feature to the platform.
|
|
8
|
+
|
|
9
|
+
### Phase 1: Requirements Analysis
|
|
10
|
+
|
|
11
|
+
**Steps:**
|
|
12
|
+
1. Gather requirements from stakeholders
|
|
13
|
+
2. Document user stories
|
|
14
|
+
3. Identify affected systems
|
|
15
|
+
4. Define success criteria
|
|
16
|
+
|
|
17
|
+
**Output:**
|
|
18
|
+
- Requirements document
|
|
19
|
+
- User stories
|
|
20
|
+
- Acceptance criteria
|
|
21
|
+
|
|
22
|
+
### Phase 2: Design
|
|
23
|
+
|
|
24
|
+
**Steps:**
|
|
25
|
+
1. Create architecture diagram
|
|
26
|
+
2. Define database schema
|
|
27
|
+
3. Design API contracts (tRPC routes)
|
|
28
|
+
4. Plan state management strategy
|
|
29
|
+
5. Identify shared types needed
|
|
30
|
+
|
|
31
|
+
**Output:**
|
|
32
|
+
```typescript
|
|
33
|
+
// Example: Enrichment feature design
|
|
34
|
+
|
|
35
|
+
// 1. Database schema (migration)
|
|
36
|
+
CREATE TABLE enrichments (
|
|
37
|
+
id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
38
|
+
lesson_id uuid REFERENCES lessons(id) ON DELETE CASCADE,
|
|
39
|
+
type enrichment_type NOT NULL,
|
|
40
|
+
status enrichment_status DEFAULT 'draft',
|
|
41
|
+
metadata jsonb,
|
|
42
|
+
created_at timestamptz DEFAULT now()
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// 2. Shared types
|
|
46
|
+
// packages/shared-types/src/enrichment.ts
|
|
47
|
+
export interface Enrichment {
|
|
48
|
+
id: string;
|
|
49
|
+
lessonId: string;
|
|
50
|
+
type: EnrichmentType;
|
|
51
|
+
status: EnrichmentStatus;
|
|
52
|
+
metadata: EnrichmentMetadata;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 3. tRPC router
|
|
56
|
+
// packages/course-gen-platform/src/server/routers/enrichments.ts
|
|
57
|
+
export const enrichmentsRouter = router({
|
|
58
|
+
list: publicProcedure
|
|
59
|
+
.input(z.object({ lessonId: z.string() }))
|
|
60
|
+
.query(async ({ input }) => { ... }),
|
|
61
|
+
|
|
62
|
+
create: publicProcedure
|
|
63
|
+
.input(CreateEnrichmentSchema)
|
|
64
|
+
.mutation(async ({ input }) => { ... }),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// 4. State management
|
|
68
|
+
// packages/web/stores/enrichment-store.ts
|
|
69
|
+
export const useEnrichmentStore = create<State>()(immer(...));
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Phase 3: Implementation
|
|
73
|
+
|
|
74
|
+
**Steps:**
|
|
75
|
+
1. Create feature branch
|
|
76
|
+
2. Implement database migration
|
|
77
|
+
3. Add shared types to `packages/shared-types`
|
|
78
|
+
4. Implement backend (tRPC routes)
|
|
79
|
+
5. Implement frontend (components + state)
|
|
80
|
+
6. Add tests
|
|
81
|
+
|
|
82
|
+
**Order of implementation:**
|
|
83
|
+
```bash
|
|
84
|
+
# 1. Shared types first (dependency for both backend and frontend)
|
|
85
|
+
packages/shared-types/src/enrichment.ts
|
|
86
|
+
|
|
87
|
+
# 2. Database migration
|
|
88
|
+
packages/course-gen-platform/supabase/migrations/YYYYMMDD_add_enrichments.sql
|
|
89
|
+
|
|
90
|
+
# 3. Backend implementation
|
|
91
|
+
packages/course-gen-platform/src/server/routers/enrichments.ts
|
|
92
|
+
packages/course-gen-platform/src/stages/stage7-enrichments/
|
|
93
|
+
|
|
94
|
+
# 4. Frontend implementation
|
|
95
|
+
packages/web/components/enrichment/
|
|
96
|
+
packages/web/app/api/enrichments/
|
|
97
|
+
packages/web/stores/enrichment-store.ts
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Phase 4: Testing
|
|
101
|
+
|
|
102
|
+
**Steps:**
|
|
103
|
+
1. Unit tests (backend logic)
|
|
104
|
+
2. Integration tests (API routes)
|
|
105
|
+
3. E2E tests (user flows)
|
|
106
|
+
4. Manual testing
|
|
107
|
+
|
|
108
|
+
**Test coverage targets:**
|
|
109
|
+
- Backend: 80%+ coverage
|
|
110
|
+
- Frontend: Critical paths only
|
|
111
|
+
- E2E: Happy path + error cases
|
|
112
|
+
|
|
113
|
+
### Phase 5: Deployment
|
|
114
|
+
|
|
115
|
+
**Steps:**
|
|
116
|
+
1. Run type-check: `pnpm type-check`
|
|
117
|
+
2. Run build: `pnpm build`
|
|
118
|
+
3. Apply migrations: `pnpm supabase db push`
|
|
119
|
+
4. Deploy backend (course-gen-platform)
|
|
120
|
+
5. Deploy frontend (web)
|
|
121
|
+
6. Monitor logs and metrics
|
|
122
|
+
|
|
123
|
+
**Rollback plan:**
|
|
124
|
+
```bash
|
|
125
|
+
# If deployment fails
|
|
126
|
+
1. Revert database migration
|
|
127
|
+
2. Rollback application deployment
|
|
128
|
+
3. Clear Redis cache if needed
|
|
129
|
+
4. Notify team
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Workflow 2: Database Schema Changes
|
|
133
|
+
|
|
134
|
+
Safe workflow for modifying database schema in production.
|
|
135
|
+
|
|
136
|
+
### Phase 1: Planning
|
|
137
|
+
|
|
138
|
+
**Checklist:**
|
|
139
|
+
- [ ] Identify affected tables
|
|
140
|
+
- [ ] Check for foreign key constraints
|
|
141
|
+
- [ ] Plan for data migration
|
|
142
|
+
- [ ] Estimate downtime (if any)
|
|
143
|
+
- [ ] Prepare rollback strategy
|
|
144
|
+
|
|
145
|
+
### Phase 2: Migration Development
|
|
146
|
+
|
|
147
|
+
**Pattern: Additive changes (safe):**
|
|
148
|
+
```sql
|
|
149
|
+
-- ✅ SAFE: Add new column with default
|
|
150
|
+
ALTER TABLE courses ADD COLUMN visibility text DEFAULT 'private';
|
|
151
|
+
|
|
152
|
+
-- ✅ SAFE: Add new table
|
|
153
|
+
CREATE TABLE course_shares (
|
|
154
|
+
id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
155
|
+
course_id uuid REFERENCES courses(id) ON DELETE CASCADE,
|
|
156
|
+
share_token text UNIQUE NOT NULL,
|
|
157
|
+
created_at timestamptz DEFAULT now()
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
-- ✅ SAFE: Add index
|
|
161
|
+
CREATE INDEX idx_courses_organization ON courses(organization_id);
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Pattern: Breaking changes (risky):**
|
|
165
|
+
```sql
|
|
166
|
+
-- ⚠️ RISKY: Rename column (breaks existing queries)
|
|
167
|
+
-- Better approach: Add new column, migrate data, deprecate old column
|
|
168
|
+
|
|
169
|
+
-- Step 1: Add new column
|
|
170
|
+
ALTER TABLE courses ADD COLUMN new_name text;
|
|
171
|
+
|
|
172
|
+
-- Step 2: Backfill data
|
|
173
|
+
UPDATE courses SET new_name = old_name;
|
|
174
|
+
|
|
175
|
+
-- Step 3: Update application code to use new_name
|
|
176
|
+
|
|
177
|
+
-- Step 4: (Later) Drop old column
|
|
178
|
+
ALTER TABLE courses DROP COLUMN old_name;
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Pattern: Data migrations:**
|
|
182
|
+
```sql
|
|
183
|
+
-- Migrate enum values
|
|
184
|
+
DO $$
|
|
185
|
+
DECLARE
|
|
186
|
+
course_record RECORD;
|
|
187
|
+
BEGIN
|
|
188
|
+
FOR course_record IN SELECT id, old_status FROM courses LOOP
|
|
189
|
+
UPDATE courses
|
|
190
|
+
SET new_status = CASE
|
|
191
|
+
WHEN old_status = 'active' THEN 'published'
|
|
192
|
+
WHEN old_status = 'inactive' THEN 'draft'
|
|
193
|
+
ELSE 'archived'
|
|
194
|
+
END
|
|
195
|
+
WHERE id = course_record.id;
|
|
196
|
+
END LOOP;
|
|
197
|
+
END $$;
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Phase 3: Testing
|
|
201
|
+
|
|
202
|
+
**Local testing:**
|
|
203
|
+
```bash
|
|
204
|
+
# 1. Start local Supabase
|
|
205
|
+
pnpm supabase start
|
|
206
|
+
|
|
207
|
+
# 2. Apply migration
|
|
208
|
+
pnpm supabase migration up
|
|
209
|
+
|
|
210
|
+
# 3. Test migration
|
|
211
|
+
# - Verify schema changes
|
|
212
|
+
# - Check data integrity
|
|
213
|
+
# - Run application locally
|
|
214
|
+
|
|
215
|
+
# 4. Rollback test
|
|
216
|
+
pnpm supabase db reset
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Staging testing:**
|
|
220
|
+
```bash
|
|
221
|
+
# 1. Apply to staging
|
|
222
|
+
pnpm supabase db push --db-url $STAGING_DB_URL
|
|
223
|
+
|
|
224
|
+
# 2. Run E2E tests
|
|
225
|
+
pnpm test:e2e
|
|
226
|
+
|
|
227
|
+
# 3. Manual QA
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Phase 4: Production Deployment
|
|
231
|
+
|
|
232
|
+
**Pre-deployment:**
|
|
233
|
+
```bash
|
|
234
|
+
# 1. Backup database (if critical change)
|
|
235
|
+
pg_dump -h $PROD_HOST -U $PROD_USER -d $PROD_DB > backup.sql
|
|
236
|
+
|
|
237
|
+
# 2. Announce maintenance window (if needed)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Deployment:**
|
|
241
|
+
```bash
|
|
242
|
+
# 1. Apply migration
|
|
243
|
+
pnpm supabase db push --db-url $PROD_DB_URL
|
|
244
|
+
|
|
245
|
+
# 2. Monitor for errors
|
|
246
|
+
tail -f /var/log/postgres/postgresql.log
|
|
247
|
+
|
|
248
|
+
# 3. Verify schema
|
|
249
|
+
psql -h $PROD_HOST -U $PROD_USER -d $PROD_DB -c "\d+ table_name"
|
|
250
|
+
|
|
251
|
+
# 4. Check application logs
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Post-deployment:**
|
|
255
|
+
```bash
|
|
256
|
+
# 1. Run smoke tests
|
|
257
|
+
curl -X GET https://api.example.com/health
|
|
258
|
+
|
|
259
|
+
# 2. Monitor metrics
|
|
260
|
+
# - Query performance
|
|
261
|
+
# - Error rates
|
|
262
|
+
# - Response times
|
|
263
|
+
|
|
264
|
+
# 3. Generate updated TypeScript types
|
|
265
|
+
pnpm supabase gen types typescript --project-id PROJECT_REF > database.types.ts
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Workflow 3: Performance Optimization
|
|
269
|
+
|
|
270
|
+
Systematic approach to identifying and fixing performance issues.
|
|
271
|
+
|
|
272
|
+
### Phase 1: Profiling
|
|
273
|
+
|
|
274
|
+
**Frontend profiling:**
|
|
275
|
+
```typescript
|
|
276
|
+
// React DevTools Profiler
|
|
277
|
+
import { Profiler } from 'react';
|
|
278
|
+
|
|
279
|
+
<Profiler id="CourseList" onRender={onRenderCallback}>
|
|
280
|
+
<CourseList />
|
|
281
|
+
</Profiler>
|
|
282
|
+
|
|
283
|
+
// Browser Performance API
|
|
284
|
+
performance.mark('start-render');
|
|
285
|
+
renderComponent();
|
|
286
|
+
performance.mark('end-render');
|
|
287
|
+
performance.measure('render-time', 'start-render', 'end-render');
|
|
288
|
+
|
|
289
|
+
// Lighthouse audit
|
|
290
|
+
npx lighthouse https://app.example.com --view
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**Backend profiling:**
|
|
294
|
+
```bash
|
|
295
|
+
# Database query performance
|
|
296
|
+
EXPLAIN ANALYZE SELECT * FROM courses WHERE organization_id = 'uuid';
|
|
297
|
+
|
|
298
|
+
# Node.js profiling
|
|
299
|
+
node --inspect packages/course-gen-platform/dist/server.js
|
|
300
|
+
|
|
301
|
+
# Chrome DevTools -> chrome://inspect
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Phase 2: Identify Bottlenecks
|
|
305
|
+
|
|
306
|
+
**Common bottlenecks:**
|
|
307
|
+
|
|
308
|
+
1. **N+1 queries:**
|
|
309
|
+
```typescript
|
|
310
|
+
// ❌ BAD: N+1 queries
|
|
311
|
+
const courses = await db.from('courses').select('*');
|
|
312
|
+
for (const course of courses) {
|
|
313
|
+
const lessons = await db.from('lessons').select('*').eq('course_id', course.id);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// ✅ GOOD: Single query with join
|
|
317
|
+
const coursesWithLessons = await db
|
|
318
|
+
.from('courses')
|
|
319
|
+
.select('*, lessons(*)')
|
|
320
|
+
.eq('organization_id', orgId);
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
2. **Missing indexes:**
|
|
324
|
+
```sql
|
|
325
|
+
-- Find slow queries
|
|
326
|
+
SELECT query, calls, total_time, mean_time
|
|
327
|
+
FROM pg_stat_statements
|
|
328
|
+
ORDER BY total_time DESC
|
|
329
|
+
LIMIT 10;
|
|
330
|
+
|
|
331
|
+
-- Add index
|
|
332
|
+
CREATE INDEX idx_lessons_course_id ON lessons(course_id);
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
3. **Large bundle size:**
|
|
336
|
+
```bash
|
|
337
|
+
# Analyze bundle
|
|
338
|
+
pnpm next build
|
|
339
|
+
pnpm @next/bundle-analyzer
|
|
340
|
+
|
|
341
|
+
# Fix: Code splitting
|
|
342
|
+
const HeavyComponent = lazy(() => import('./HeavyComponent'));
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
4. **Unnecessary re-renders:**
|
|
346
|
+
```typescript
|
|
347
|
+
// ❌ BAD: Re-renders on every state change
|
|
348
|
+
const { allState } = useStore();
|
|
349
|
+
|
|
350
|
+
// ✅ GOOD: Granular selectors
|
|
351
|
+
const courseName = useStore((s) => s.course.name);
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Phase 3: Implement Fixes
|
|
355
|
+
|
|
356
|
+
**Database optimizations:**
|
|
357
|
+
```sql
|
|
358
|
+
-- 1. Add indexes
|
|
359
|
+
CREATE INDEX CONCURRENTLY idx_courses_org_id ON courses(organization_id);
|
|
360
|
+
|
|
361
|
+
-- 2. Optimize queries
|
|
362
|
+
-- Before: Full table scan
|
|
363
|
+
SELECT * FROM courses WHERE deleted_at IS NULL;
|
|
364
|
+
|
|
365
|
+
-- After: Index-only scan
|
|
366
|
+
CREATE INDEX idx_active_courses ON courses(id) WHERE deleted_at IS NULL;
|
|
367
|
+
|
|
368
|
+
-- 3. Materialized views for complex aggregations
|
|
369
|
+
CREATE MATERIALIZED VIEW course_stats AS
|
|
370
|
+
SELECT
|
|
371
|
+
organization_id,
|
|
372
|
+
COUNT(*) as total_courses,
|
|
373
|
+
SUM(lesson_count) as total_lessons
|
|
374
|
+
FROM courses
|
|
375
|
+
WHERE deleted_at IS NULL
|
|
376
|
+
GROUP BY organization_id;
|
|
377
|
+
|
|
378
|
+
-- Refresh periodically
|
|
379
|
+
REFRESH MATERIALIZED VIEW CONCURRENTLY course_stats;
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Frontend optimizations:**
|
|
383
|
+
```typescript
|
|
384
|
+
// 1. Memoization
|
|
385
|
+
const expensiveValue = useMemo(() => {
|
|
386
|
+
return computeExpensiveValue(data);
|
|
387
|
+
}, [data]);
|
|
388
|
+
|
|
389
|
+
// 2. Virtualization (react-window)
|
|
390
|
+
import { FixedSizeList } from 'react-window';
|
|
391
|
+
|
|
392
|
+
<FixedSizeList
|
|
393
|
+
height={600}
|
|
394
|
+
itemCount={courses.length}
|
|
395
|
+
itemSize={80}
|
|
396
|
+
>
|
|
397
|
+
{({ index, style }) => (
|
|
398
|
+
<CourseItem course={courses[index]} style={style} />
|
|
399
|
+
)}
|
|
400
|
+
</FixedSizeList>
|
|
401
|
+
|
|
402
|
+
// 3. Image optimization
|
|
403
|
+
import Image from 'next/image';
|
|
404
|
+
|
|
405
|
+
<Image
|
|
406
|
+
src="/course-image.jpg"
|
|
407
|
+
width={400}
|
|
408
|
+
height={300}
|
|
409
|
+
placeholder="blur"
|
|
410
|
+
loading="lazy"
|
|
411
|
+
/>
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
**Backend optimizations:**
|
|
415
|
+
```typescript
|
|
416
|
+
// 1. Caching with Redis
|
|
417
|
+
const cached = await redis.get(`course:${courseId}`);
|
|
418
|
+
if (cached) return JSON.parse(cached);
|
|
419
|
+
|
|
420
|
+
const course = await db.from('courses').select('*').eq('id', courseId).single();
|
|
421
|
+
await redis.set(`course:${courseId}`, JSON.stringify(course), { ex: 300 });
|
|
422
|
+
|
|
423
|
+
// 2. Batch operations
|
|
424
|
+
// Before: N individual inserts
|
|
425
|
+
for (const lesson of lessons) {
|
|
426
|
+
await db.from('lessons').insert(lesson);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// After: Single batch insert
|
|
430
|
+
await db.from('lessons').insert(lessons);
|
|
431
|
+
|
|
432
|
+
// 3. Pagination
|
|
433
|
+
const { data, count } = await db
|
|
434
|
+
.from('courses')
|
|
435
|
+
.select('*', { count: 'exact' })
|
|
436
|
+
.range(offset, offset + limit - 1);
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### Phase 4: Measure Results
|
|
440
|
+
|
|
441
|
+
**Metrics to track:**
|
|
442
|
+
```typescript
|
|
443
|
+
// 1. Frontend metrics
|
|
444
|
+
const metrics = {
|
|
445
|
+
FCP: 'First Contentful Paint',
|
|
446
|
+
LCP: 'Largest Contentful Paint',
|
|
447
|
+
FID: 'First Input Delay',
|
|
448
|
+
CLS: 'Cumulative Layout Shift',
|
|
449
|
+
TTFB: 'Time to First Byte',
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
// 2. Backend metrics
|
|
453
|
+
const dbMetrics = {
|
|
454
|
+
queryTime: 'Average query execution time',
|
|
455
|
+
throughput: 'Queries per second',
|
|
456
|
+
cacheHitRate: 'Redis cache hit rate',
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
// 3. Set targets
|
|
460
|
+
const targets = {
|
|
461
|
+
FCP: '< 1.8s',
|
|
462
|
+
LCP: '< 2.5s',
|
|
463
|
+
FID: '< 100ms',
|
|
464
|
+
queryTime: '< 50ms',
|
|
465
|
+
cacheHitRate: '> 80%',
|
|
466
|
+
};
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
## Workflow 4: Adding API Endpoints
|
|
470
|
+
|
|
471
|
+
Workflow for adding new tRPC routes.
|
|
472
|
+
|
|
473
|
+
### Step 1: Define Input Schema
|
|
474
|
+
|
|
475
|
+
```typescript
|
|
476
|
+
// packages/shared-types/src/schemas/course.ts
|
|
477
|
+
import { z } from 'zod';
|
|
478
|
+
|
|
479
|
+
export const CreateCourseSchema = z.object({
|
|
480
|
+
title: z.string().min(3).max(100),
|
|
481
|
+
description: z.string().optional(),
|
|
482
|
+
organizationId: z.string().uuid(),
|
|
483
|
+
visibility: z.enum(['private', 'organization', 'public']).default('private'),
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
export type CreateCourseInput = z.infer<typeof CreateCourseSchema>;
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Step 2: Implement Router
|
|
490
|
+
|
|
491
|
+
```typescript
|
|
492
|
+
// packages/course-gen-platform/src/server/routers/courses.ts
|
|
493
|
+
import { router, publicProcedure } from '../trpc';
|
|
494
|
+
import { CreateCourseSchema } from '@megacampus/shared-types';
|
|
495
|
+
import { getSupabaseAdmin } from '../../shared/supabase/admin';
|
|
496
|
+
|
|
497
|
+
export const coursesRouter = router({
|
|
498
|
+
list: publicProcedure
|
|
499
|
+
.input(z.object({
|
|
500
|
+
organizationId: z.string().uuid(),
|
|
501
|
+
limit: z.number().min(1).max(100).default(10),
|
|
502
|
+
offset: z.number().min(0).default(0),
|
|
503
|
+
}))
|
|
504
|
+
.query(async ({ input }) => {
|
|
505
|
+
const admin = getSupabaseAdmin();
|
|
506
|
+
|
|
507
|
+
const { data, error, count } = await admin
|
|
508
|
+
.from('courses')
|
|
509
|
+
.select('*', { count: 'exact' })
|
|
510
|
+
.eq('organization_id', input.organizationId)
|
|
511
|
+
.is('deleted_at', null)
|
|
512
|
+
.range(input.offset, input.offset + input.limit - 1);
|
|
513
|
+
|
|
514
|
+
if (error) throw new Error(error.message);
|
|
515
|
+
|
|
516
|
+
return { courses: data, total: count };
|
|
517
|
+
}),
|
|
518
|
+
|
|
519
|
+
create: publicProcedure
|
|
520
|
+
.input(CreateCourseSchema)
|
|
521
|
+
.mutation(async ({ input }) => {
|
|
522
|
+
const admin = getSupabaseAdmin();
|
|
523
|
+
|
|
524
|
+
const { data, error } = await admin
|
|
525
|
+
.from('courses')
|
|
526
|
+
.insert({
|
|
527
|
+
title: input.title,
|
|
528
|
+
description: input.description,
|
|
529
|
+
organization_id: input.organizationId,
|
|
530
|
+
visibility: input.visibility,
|
|
531
|
+
})
|
|
532
|
+
.select()
|
|
533
|
+
.single();
|
|
534
|
+
|
|
535
|
+
if (error) throw new Error(error.message);
|
|
536
|
+
|
|
537
|
+
return data;
|
|
538
|
+
}),
|
|
539
|
+
});
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### Step 3: Add to App Router
|
|
543
|
+
|
|
544
|
+
```typescript
|
|
545
|
+
// packages/course-gen-platform/src/server/routers/_app.ts
|
|
546
|
+
import { coursesRouter } from './courses';
|
|
547
|
+
|
|
548
|
+
export const appRouter = router({
|
|
549
|
+
courses: coursesRouter,
|
|
550
|
+
// ... other routers
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
export type AppRouter = typeof appRouter;
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
### Step 4: Use in Frontend
|
|
557
|
+
|
|
558
|
+
```typescript
|
|
559
|
+
// packages/web/app/courses/page.tsx
|
|
560
|
+
'use client';
|
|
561
|
+
|
|
562
|
+
import { trpc } from '@/lib/trpc';
|
|
563
|
+
|
|
564
|
+
export default function CoursesPage() {
|
|
565
|
+
const { data, isLoading } = trpc.courses.list.useQuery({
|
|
566
|
+
organizationId: 'org-uuid',
|
|
567
|
+
limit: 10,
|
|
568
|
+
offset: 0,
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
if (isLoading) return <Skeleton />;
|
|
572
|
+
|
|
573
|
+
return (
|
|
574
|
+
<div>
|
|
575
|
+
{data?.courses.map(course => (
|
|
576
|
+
<CourseCard key={course.id} course={course} />
|
|
577
|
+
))}
|
|
578
|
+
</div>
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
### Step 5: Testing
|
|
584
|
+
|
|
585
|
+
```typescript
|
|
586
|
+
// packages/course-gen-platform/tests/routers/courses.test.ts
|
|
587
|
+
import { describe, it, expect } from 'vitest';
|
|
588
|
+
import { appRouter } from '../../src/server/routers/_app';
|
|
589
|
+
|
|
590
|
+
describe('coursesRouter', () => {
|
|
591
|
+
it('should create course', async () => {
|
|
592
|
+
const caller = appRouter.createCaller({});
|
|
593
|
+
|
|
594
|
+
const result = await caller.courses.create({
|
|
595
|
+
title: 'Test Course',
|
|
596
|
+
organizationId: 'org-uuid',
|
|
597
|
+
visibility: 'private',
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
expect(result).toHaveProperty('id');
|
|
601
|
+
expect(result.title).toBe('Test Course');
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
it('should validate input', async () => {
|
|
605
|
+
const caller = appRouter.createCaller({});
|
|
606
|
+
|
|
607
|
+
await expect(
|
|
608
|
+
caller.courses.create({ title: 'AB' }) // Too short
|
|
609
|
+
).rejects.toThrow();
|
|
610
|
+
});
|
|
611
|
+
});
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
## Workflow 5: Monorepo Dependency Management
|
|
615
|
+
|
|
616
|
+
Managing dependencies across packages.
|
|
617
|
+
|
|
618
|
+
### Adding Dependencies
|
|
619
|
+
|
|
620
|
+
```bash
|
|
621
|
+
# Add to specific package
|
|
622
|
+
pnpm --filter web add react-query
|
|
623
|
+
pnpm --filter course-gen-platform add bullmq
|
|
624
|
+
|
|
625
|
+
# Add to all packages
|
|
626
|
+
pnpm -r add lodash
|
|
627
|
+
|
|
628
|
+
# Add to root (devDependencies)
|
|
629
|
+
pnpm add -D -w prettier
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### Internal Dependencies
|
|
633
|
+
|
|
634
|
+
```json
|
|
635
|
+
// packages/web/package.json
|
|
636
|
+
{
|
|
637
|
+
"dependencies": {
|
|
638
|
+
"@megacampus/shared-types": "workspace:*",
|
|
639
|
+
"@megacampus/trpc-client-sdk": "workspace:*"
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
### Dependency Updates
|
|
645
|
+
|
|
646
|
+
```bash
|
|
647
|
+
# Check outdated
|
|
648
|
+
pnpm outdated
|
|
649
|
+
|
|
650
|
+
# Update all
|
|
651
|
+
pnpm update --latest
|
|
652
|
+
|
|
653
|
+
# Update specific package
|
|
654
|
+
pnpm --filter web update react@latest
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
## Workflow 6: Error Handling
|
|
658
|
+
|
|
659
|
+
Consistent error handling across the stack.
|
|
660
|
+
|
|
661
|
+
### Backend Error Handling
|
|
662
|
+
|
|
663
|
+
```typescript
|
|
664
|
+
// Custom error classes
|
|
665
|
+
class AppError extends Error {
|
|
666
|
+
constructor(
|
|
667
|
+
message: string,
|
|
668
|
+
public statusCode: number,
|
|
669
|
+
public code: string
|
|
670
|
+
) {
|
|
671
|
+
super(message);
|
|
672
|
+
this.name = 'AppError';
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// tRPC error handling
|
|
677
|
+
import { TRPCError } from '@trpc/server';
|
|
678
|
+
|
|
679
|
+
export const coursesRouter = router({
|
|
680
|
+
get: publicProcedure
|
|
681
|
+
.input(z.object({ id: z.string().uuid() }))
|
|
682
|
+
.query(async ({ input }) => {
|
|
683
|
+
const { data, error } = await admin
|
|
684
|
+
.from('courses')
|
|
685
|
+
.select('*')
|
|
686
|
+
.eq('id', input.id)
|
|
687
|
+
.single();
|
|
688
|
+
|
|
689
|
+
if (error) {
|
|
690
|
+
throw new TRPCError({
|
|
691
|
+
code: 'NOT_FOUND',
|
|
692
|
+
message: 'Course not found',
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
return data;
|
|
697
|
+
}),
|
|
698
|
+
});
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
### Frontend Error Handling
|
|
702
|
+
|
|
703
|
+
```typescript
|
|
704
|
+
// Error boundary
|
|
705
|
+
'use client';
|
|
706
|
+
|
|
707
|
+
import { useEffect } from 'react';
|
|
708
|
+
|
|
709
|
+
export default function Error({
|
|
710
|
+
error,
|
|
711
|
+
reset,
|
|
712
|
+
}: {
|
|
713
|
+
error: Error;
|
|
714
|
+
reset: () => void;
|
|
715
|
+
}) {
|
|
716
|
+
useEffect(() => {
|
|
717
|
+
console.error(error);
|
|
718
|
+
}, [error]);
|
|
719
|
+
|
|
720
|
+
return (
|
|
721
|
+
<div>
|
|
722
|
+
<h2>Something went wrong!</h2>
|
|
723
|
+
<button onClick={() => reset()}>Try again</button>
|
|
724
|
+
</div>
|
|
725
|
+
);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// Toast notifications
|
|
729
|
+
import { toast } from 'sonner';
|
|
730
|
+
|
|
731
|
+
const createCourse = trpc.courses.create.useMutation({
|
|
732
|
+
onSuccess: () => {
|
|
733
|
+
toast.success('Course created successfully');
|
|
734
|
+
},
|
|
735
|
+
onError: (error) => {
|
|
736
|
+
toast.error(error.message || 'Failed to create course');
|
|
737
|
+
},
|
|
738
|
+
});
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
## Conclusion
|
|
742
|
+
|
|
743
|
+
These workflows provide systematic approaches to common development tasks. Key principles:
|
|
744
|
+
|
|
745
|
+
1. **Plan before implementing** - Design docs, architecture diagrams
|
|
746
|
+
2. **Safety first** - Rollback plans, staging tests, gradual rollouts
|
|
747
|
+
3. **Measure everything** - Profiling, metrics, monitoring
|
|
748
|
+
4. **Consistent patterns** - Follow established conventions
|
|
749
|
+
5. **Type safety** - Zod schemas, tRPC, shared types
|