diff --git a/DATABASE_SCHEMA_FIELD_MAPPING_GUIDE.md b/DATABASE_SCHEMA_FIELD_MAPPING_GUIDE.md new file mode 100644 index 00000000..1ba56acc --- /dev/null +++ b/DATABASE_SCHEMA_FIELD_MAPPING_GUIDE.md @@ -0,0 +1,264 @@ +# Database Schema vs Model Field Mapping Guide + +## Overview +This guide documents the critical database schema mismatches in the IGNY8 project that cause 500 errors. These mismatches occur because the database uses OLD column names while Django models use NEW refactored field names. + +--- + +## Critical Issue: Database Column Name Mismatches + +### Problem Statement +During the "Stage 1 Refactor", model field names were changed but database column names were NOT renamed. This causes: +- **500 Internal Server Error** - When Django tries to query non-existent columns +- **AttributeError** - When code references old field names on model instances +- **FieldError** - When filtering/querying with old field names + +### Root Cause +The refactor changed the **Python model field names** but the **actual PostgreSQL database columns** still use the old names. Django expects the new field names but the database has the old column names. + +--- + +## Known Database vs Model Mismatches + +### Content Model (`igny8_content` table) + +| Model Field Name | Database Column Name | Fix Required | +|-----------------|---------------------|--------------| +| `content_html` | `html_content` | Add `db_column='html_content'` | +| `content_type` | `entity_type` | Add `db_column='entity_type'` | +| `content_structure` | `cluster_role` | Add `db_column='cluster_role'` | + +**Location:** `backend/igny8_core/business/content/models.py` - Content model + +**Additional Fields to Include:** +- `external_type` - exists in database, must be in model +- `sync_status` - exists in database, must be in model + +### Tasks Model (`igny8_tasks` table) + +| Model Field Name | Database Column Name | Fix Required | +|-----------------|---------------------|--------------| +| `content_type` | `entity_type` | Add `db_column='entity_type'` | +| `content_structure` | `cluster_role` | Add `db_column='cluster_role'` | +| `taxonomy_term` | `taxonomy_id` | Add `db_column='taxonomy_id'` | +| `idea` | `idea_id` | Add `db_column='idea_id'` | +| `keywords` | `keywords` (text) | Change from ManyToManyField to TextField | + +**Location:** `backend/igny8_core/business/content/models.py` - Tasks model + +### ContentTaxonomy Relations (`igny8_content_taxonomy_relations` table) + +| Model Expects | Database Has | Fix Required | +|--------------|-------------|--------------| +| `contenttaxonomy_id` | `taxonomy_id` | Create through model with `db_column` | +| Auto M2M table | Custom table | Use `through='ContentTaxonomyRelation'` | + +**Location:** Must create `ContentTaxonomyRelation` through model with explicit `db_column` settings + +--- + +## Common Code Reference Errors + +### Issue: Code Still Uses Old Field Names + +Even after fixing the model, **view code** might still reference old field names: + +**Wrong References to Fix:** +- `content.entity_type` → Should be `content.content_type` +- `content.cluster_role` → Should be `content.content_structure` +- `content.html_content` → Should be `content.content_html` +- `content.taxonomies` → Should be `content.taxonomy_terms` + +**Files to Check:** +- `backend/igny8_core/modules/writer/views.py` +- `backend/igny8_core/modules/integration/views.py` +- `backend/igny8_core/business/*/services/*.py` +- `backend/igny8_core/ai/functions/*.py` + +**Search Commands:** +```bash +grep -r "\.entity_type" backend/igny8_core/ +grep -r "\.cluster_role" backend/igny8_core/ +grep -r "\.html_content" backend/igny8_core/ +grep -r "\.taxonomies" backend/igny8_core/ +``` + +--- + +## Diagnostic Checklist for 500 Errors + +When encountering 500 Internal Server Errors, follow this checklist: + +### Step 1: Check Backend Logs +```bash +docker logs --tail=100 igny8_backend 2>&1 | grep -A 20 "Traceback" +docker logs igny8_backend 2>&1 | grep "UndefinedColumn\|does not exist" +``` + +### Step 2: Identify Error Type + +**A. ProgrammingError: column does not exist** +- Error shows: `column igny8_content.field_name does not exist` +- **Action:** Database has different column name than model expects +- **Fix:** Add `db_column='actual_database_column_name'` to model field + +**B. AttributeError: object has no attribute** +- Error shows: `'Content' object has no attribute 'entity_type'` +- **Action:** Code references old field name +- **Fix:** Update code to use new field name from model + +**C. FieldError: Cannot resolve keyword** +- Error shows: `Cannot resolve keyword 'entity_type' into field` +- **Action:** Query/filter uses old field name +- **Fix:** Update queryset filters to use new field names + +### Step 3: Verify Database Schema +```bash +docker exec igny8_backend python manage.py shell -c " +from django.db import connection +cursor = connection.cursor() +cursor.execute('SELECT column_name FROM information_schema.columns WHERE table_name = %s ORDER BY ordinal_position', ['igny8_content']) +print('\n'.join([row[0] for row in cursor.fetchall()])) +" +``` + +### Step 4: Compare Against Model +Check if model field names match database column names. If not, add `db_column` attribute. + +### Step 5: Search for Code References +After fixing model, search all code for references to old field names and update them. + +--- + +## Prevention: Pre-Refactor Checklist + +Before doing ANY database model refactoring: + +### 1. Document Current State +- [ ] List all current database column names +- [ ] List all current model field names +- [ ] Identify any existing `db_column` mappings + +### 2. Plan Migration Strategy +- [ ] Decide: Rename database columns OR add `db_column` mappings? +- [ ] If renaming: Create migration to rename columns +- [ ] If mapping: Document which fields need `db_column` + +### 3. Update All Code References +- [ ] Search codebase for old field name references +- [ ] Update view code, serializers, services +- [ ] Update filters, querysets, aggregations +- [ ] Update AI functions and background tasks + +### 4. Test Before Deploy +- [ ] Run migrations on development database +- [ ] Test all API endpoints with authentication +- [ ] Check logs for database errors +- [ ] Verify no AttributeError or FieldError exceptions + +### 5. Maintain Documentation +- [ ] Update this guide with new mappings +- [ ] Document why `db_column` is needed +- [ ] Note any related field name changes + +--- + +## Quick Fix Template + +When you find a database mismatch: + +```python +# In the model file (e.g., backend/igny8_core/business/content/models.py) + +# OLD (causes 500 error): +content_type = models.CharField(max_length=100) + +# FIXED (maps to actual database column): +content_type = models.CharField( + max_length=100, + db_column='entity_type', # <- Maps to actual database column name + blank=True, + null=True +) +``` + +Then search and replace code references: +```bash +# Find all references to old field name +grep -rn "\.entity_type" backend/ + +# Update to new field name +sed -i 's/\.entity_type/.content_type/g' backend/igny8_core/modules/writer/views.py +``` + +--- + +## Frontend Common Issues + +### Issue: Undefined Variables +**Error:** `ReferenceError: variableName is not defined` + +**Common Causes:** +- Variable declared but removed during refactor +- Variable in dependency array but not defined in component +- Import removed but variable still referenced + +**Files to Check:** +- `frontend/src/pages/Writer/Tasks.tsx` +- `frontend/src/pages/Writer/Content.tsx` +- Any component showing console loops + +**Fix:** Remove from dependency arrays or add proper state declaration + +--- + +## Testing Endpoints After Fixes + +Use this command to verify all critical endpoints: + +```bash +TOKEN=$(curl -s -X POST "https://api.igny8.com/api/v1/auth/login/" \ + -H "Content-Type: application/json" \ + -d '{"email":"dev@igny8.com","password":"dev123456"}' | \ + python3 -c "import sys, json; print(json.load(sys.stdin)['data']['access'])") + +# Test each endpoint +curl -s "https://api.igny8.com/api/v1/writer/content/?site_id=5&page_size=1" \ + -H "Authorization: Bearer $TOKEN" | python3 -m json.tool + +curl -s "https://api.igny8.com/api/v1/planner/clusters/?site_id=5&page_size=1" \ + -H "Authorization: Bearer $TOKEN" | python3 -m json.tool + +curl -s "https://api.igny8.com/api/v1/writer/tasks/?site_id=5&page_size=1" \ + -H "Authorization: Bearer $TOKEN" | python3 -m json.tool +``` + +**Success Indicator:** Response should have `"success": true`, not `"success": false` with error. + +--- + +## Status Codes Quick Reference + +| Code | Meaning | Common Cause | Fix | +|------|---------|--------------|-----| +| 500 | Internal Server Error | Database column mismatch, code error | Check logs, fix model or code | +| 403 | Forbidden / Auth Required | Normal - means endpoint works but needs auth | Login first, use Bearer token | +| 404 | Not Found | URL wrong or object doesn't exist | Check URL, verify ID exists | +| 400 | Bad Request | Invalid data sent | Check request payload | + +**Important:** If you see 403 instead of 500 after a fix, that's SUCCESS - it means the endpoint works and just needs authentication. + +--- + +## Summary + +**Key Principle:** The database schema is the source of truth. Models must map to actual database column names, not the other way around (unless you run migrations to rename columns). + +**Golden Rule:** After ANY refactor that changes field names: +1. Check if database columns were actually renamed +2. If not, add `db_column` mappings in models +3. Update all code references to use NEW field names +4. Test all endpoints with authentication +5. Check logs for database errors + +**Remember:** A 500 error from a database column mismatch will cascade - fixing the model isn't enough, you must also update all code that references the old field names. diff --git a/api-typescipt-console-400-500-errors.md b/api-typescipt-console-400-500-errors.md new file mode 100644 index 00000000..7d5d0439 --- /dev/null +++ b/api-typescipt-console-400-500-errors.md @@ -0,0 +1,2747 @@ +Failed to load resource: the server responded with a status of 500 ()Understand this error +api.ts:323 API Error: Objectendpoint: "/v1/writer/content/?site_id=5&page=1&page_size=20&ordering=-created_at"errorData: {success: false, error: 'Internal server error', request_id: '473179e9-a1f4-4b70-b348-f5bcf65668fd'}message: "Internal server error"status: 500type: "HTTP_ERROR"[[Prototype]]: Object +fetchAPI @ api.ts:323Understand this error +api.igny8.com/api/v1/writer/content/?site_id=5&page=1&page_size=20&ordering=-created_at:1 Failed to load resource: the server responded with a status of 500 ()Understand this error +api.ts:323 API Error: + +on this page + +https://app.igny8.com/sites/5/content + +======================================== +https://app.igny8.com/planner/clusters + +react-dom_client.js?v=6efb65b6:17804 Download the React DevTools for a better development experience: https://react.dev/link/react-devtools +api.ts:141 GET https://api.igny8.com/api/v1/planner/clusters/?site_id=5§or_id=16&page=1&page_size=10&ordering=name 500 (Internal Server Error) +fetchAPI @ api.ts:141 +fetchClusters @ api.ts:630 +(anonymous) @ Clusters.tsx:115 +(anonymous) @ Clusters.tsx:134 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9297 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9290 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9243 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/planner/clusters/?site_id=5§or_id=16&page=1&page_size=10&ordering=name', errorData: {…}} +fetchAPI @ api.ts:323 +await in fetchAPI +fetchClusters @ api.ts:630 +(anonymous) @ Clusters.tsx:115 +(anonymous) @ Clusters.tsx:134 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9297 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9290 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9243 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +Clusters.tsx:125 Error loading clusters: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Clusters.tsx:115:20 +(anonymous) @ Clusters.tsx:125 +await in (anonymous) +(anonymous) @ Clusters.tsx:134 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9297 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9290 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9243 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:141 GET https://api.igny8.com/api/v1/planner/clusters/?site_id=5§or_id=16&page=1&page_size=10&ordering=name 500 (Internal Server Error) +fetchAPI @ api.ts:141 +fetchClusters @ api.ts:630 +(anonymous) @ Clusters.tsx:115 +(anonymous) @ Clusters.tsx:134 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9297 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9290 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9312 +doubleInvokeEffectsOnFiber @ react-dom_client.js?v=6efb65b6:11282 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11263 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +commitDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11290 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11126 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/planner/clusters/?site_id=5§or_id=16&page=1&page_size=10&ordering=name', errorData: {…}} +fetchAPI @ api.ts:323 +await in fetchAPI +fetchClusters @ api.ts:630 +(anonymous) @ Clusters.tsx:115 +(anonymous) @ Clusters.tsx:134 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9297 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9290 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9312 +doubleInvokeEffectsOnFiber @ react-dom_client.js?v=6efb65b6:11282 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11263 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +commitDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11290 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11126 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +Clusters.tsx:125 Error loading clusters: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Clusters.tsx:115:20 +(anonymous) @ Clusters.tsx:125 +await in (anonymous) +(anonymous) @ Clusters.tsx:134 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9297 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9290 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9312 +doubleInvokeEffectsOnFiber @ react-dom_client.js?v=6efb65b6:11282 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11263 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +commitDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11290 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11126 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:141 GET https://api.igny8.com/api/v1/planner/clusters/?site_id=5§or_id=16&page=1&page_size=10&ordering=name 500 (Internal Server Error) +fetchAPI @ api.ts:141 +fetchClusters @ api.ts:630 +(anonymous) @ Clusters.tsx:115 +(anonymous) @ Clusters.tsx:159 +setTimeout +(anonymous) @ Clusters.tsx:157 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9297 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9290 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9312 +doubleInvokeEffectsOnFiber @ react-dom_client.js?v=6efb65b6:11282 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11263 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +commitDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11290 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11126 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/planner/clusters/?site_id=5§or_id=16&page=1&page_size=10&ordering=name', errorData: {…}} +fetchAPI @ api.ts:323 +await in fetchAPI +fetchClusters @ api.ts:630 +(anonymous) @ Clusters.tsx:115 +(anonymous) @ Clusters.tsx:159 +setTimeout +(anonymous) @ Clusters.tsx:157 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9297 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9290 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9312 +doubleInvokeEffectsOnFiber @ react-dom_client.js?v=6efb65b6:11282 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11263 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +commitDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11290 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11126 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +Clusters.tsx:125 Error loading clusters: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Clusters.tsx:115:20 +(anonymous) @ Clusters.tsx:125 +await in (anonymous) +(anonymous) @ Clusters.tsx:159 +setTimeout +(anonymous) @ Clusters.tsx:157 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9297 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9290 +recursivelyTraverseReconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9276 +reconnectPassiveEffects @ react-dom_client.js?v=6efb65b6:9312 +doubleInvokeEffectsOnFiber @ react-dom_client.js?v=6efb65b6:11282 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11263 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +recursivelyTraverseAndDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11259 +commitDoubleInvokeEffectsInDEV @ react-dom_client.js?v=6efb65b6:11290 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11126 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 + + +================== + + Download the React DevTools for a better development experience: https://react.dev/link/react-devtools +api.igny8.com/api/v1/planner/clusters/?site_id=5§or_id=16&page=1&page_size=10&ordering=name:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading clusters: +(anonymous) @ Clusters.tsx?t=1764143872332:113 +api.igny8.com/api/v1/planner/clusters/?site_id=5§or_id=16&page=1&page_size=10&ordering=name:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading clusters: +(anonymous) @ Clusters.tsx?t=1764143872332:113 +api.igny8.com/api/v1/planner/clusters/?site_id=5§or_id=16&page=1&page_size=10&ordering=name:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading clusters: +(anonymous) @ Clusters.tsx?t=1764143872332:113 +content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at', errorData: {…}} +fetchAPI @ api.ts:323 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at', errorData: {…}} +fetchAPI @ api.ts:323 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +api.ts:141 GET https://api.igny8.com/api/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at 500 (Internal Server Error) +fetchAPI @ api.ts:141 +fetchContent @ api.ts:2083 +(anonymous) @ Content.tsx:74 +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:141 GET https://api.igny8.com/api/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at 500 (Internal Server Error) +fetchAPI @ api.ts:141 +fetchContent @ api.ts:2083 +(anonymous) @ Content.tsx:74 +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at', errorData: {…}} +fetchAPI @ api.ts:323 +await in fetchAPI +fetchContent @ api.ts:2083 +(anonymous) @ Content.tsx:74 +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +await in (anonymous) +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at', errorData: {…}} +fetchAPI @ api.ts:323 +await in fetchAPI +fetchContent @ api.ts:2083 +(anonymous) @ Content.tsx:74 +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +await in (anonymous) +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:141 GET https://api.igny8.com/api/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at 500 (Internal Server Error) +fetchAPI @ api.ts:141 +fetchContent @ api.ts:2083 +(anonymous) @ Content.tsx:74 +(anonymous) @ Content.tsx:122 +setTimeout +(anonymous) @ Content.tsx:120 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at', errorData: {…}} +fetchAPI @ api.ts:323 +await in fetchAPI +fetchContent @ api.ts:2083 +(anonymous) @ Content.tsx:74 +(anonymous) @ Content.tsx:122 +setTimeout +(anonymous) @ Content.tsx:120 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +await in (anonymous) +(anonymous) @ Content.tsx:122 +setTimeout +(anonymous) @ Content.tsx:120 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:141 GET https://api.igny8.com/api/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at 500 (Internal Server Error) +fetchAPI @ api.ts:141 +fetchContent @ api.ts:2083 +(anonymous) @ Content.tsx:74 +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at', errorData: {…}} +fetchAPI @ api.ts:323 +await in fetchAPI +fetchContent @ api.ts:2083 +(anonymous) @ Content.tsx:74 +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +await in (anonymous) +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:141 GET https://api.igny8.com/api/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at 500 (Internal Server Error) +fetchAPI @ api.ts:141 +fetchContent @ api.ts:2083 +(anonymous) @ Content.tsx:74 +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at', errorData: {…}} +fetchAPI @ api.ts:323 +await in fetchAPI +fetchContent @ api.ts:2083 +(anonymous) @ Content.tsx:74 +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +await in (anonymous) +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:141 GET https://api.igny8.com/api/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at 500 (Internal Server Error) +fetchAPI @ api.ts:141 +fetchContent @ api.ts:2083 +(anonymous) @ Content.tsx:74 +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at', errorData: {…}} +fetchAPI @ api.ts:323 +await in fetchAPI +fetchContent @ api.ts:2083 +(anonymous) @ Content.tsx:74 +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +Content.tsx:84 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Content.tsx:74:20 +(anonymous) @ Content.tsx:84 +await in (anonymous) +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 +api.ts:141 GET https://api.igny8.com/api/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at 500 (Internal Server Error) +fetchAPI @ api.ts:141 +fetchContent @ api.ts:2083 +(anonymous) @ Content.tsx:74 +(anonymous) @ Content.tsx:92 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 + API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10&ordering=-created_at', errorData: {…}} +fetchAPI @ api.ts:230 +await in fetchAPI +fetchContent @ api.ts:1063 +(anonymous) @ Content.tsx:70 +(anonymous) @ Content.tsx:86 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 + Error loading content: +(anonymous) @ Content.tsx:79 +await in (anonymous) +(anonymous) @ Content.tsx:86 +react-stack-bottom-frame @ react-dom_client.js?v=6efb65b6:16242 +runWithFiberInDEV @ react-dom_client.js?v=6efb65b6:726 +commitHookEffectListMount @ react-dom_client.js?v=6efb65b6:7767 +commitHookPassiveMountEffects @ react-dom_client.js?v=6efb65b6:7825 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9182 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9238 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9176 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9265 +recursivelyTraversePassiveMountEffects @ react-dom_client.js?v=6efb65b6:9163 +commitPassiveMountOnFiber @ react-dom_client.js?v=6efb65b6:9186 +flushPassiveEffects @ react-dom_client.js?v=6efb65b6:11119 +(anonymous) @ react-dom_client.js?v=6efb65b6:11042 +performWorkUntilDeadline @ react-dom_client.js?v=6efb65b6:35 + +writer/content + +=========================== +https://app.igny8.com/writer/tasks + +Something went wrong +entityTypeFilter is not defined + +Reload Page +Error Details +ReferenceError: entityTypeFilter is not defined + at Tasks (https://app.igny8.com/src/pages/Writer/Tasks.tsx?t=1764143872329:131:78) + at react-stack-bottom-frame (https://app.igny8.com/node_modules/.vite/deps/react-dom_client.js?v=6efb65b6:16192:20) + at renderWithHooks (https://app.igny8.com/node_modules/.vite/deps/react-dom_client.js?v=6efb65b6:4306:24) + at updateFunctionComponent (https://app.igny8.com/node_modules/.vite/deps/react-dom_client.js?v=6efb65b6:5972:21) + at beginWork (https://app.igny8.com/node_modules/.vite/deps/react-dom_client.js?v=6efb65b6:7007:199) + at runWithFiberInDEV (https://app.igny8.com/node_modules/.vite/deps/react-dom_client.js?v=6efb65b6:726:18) + at performUnitOfWork (https://app.igny8.com/node_modules/.vite/deps/react-dom_client.js?v=6efb65b6:10831:98) + at workLoopSync (https://app.igny8.com/node_modules/.vite/deps/react-dom_client.js?v=6efb65b6:10692:43) + at renderRootSync (https://app.igny8.com/node_modules/.vite/deps/react-dom_client.js?v=6efb65b6:10675:13) + at performWorkOnRoot (https://app.igny8.com/node_modules/.vite/deps/react-dom_cl + + ================================ + + home apge (dashboard / file name home.tsx) + +react-dom_client.js?v=6efb65b6:17804 Download the React DevTools for a better development experience: https://react.dev/link/react-devtools +api.igny8.com/api/v1/planner/clusters/?site_id=5§or_id=16&page_size=1:1 Failed to load resource: the server responded with a status of 500 () +api.igny8.com/api/v1/writer/tasks/?site_id=5§or_id=16&page_size=1:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +Home.tsx:503 Error fetching insights: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Promise.all (/index 1) + at async fetchAppInsights (Home.tsx:439:85) +fetchAppInsights @ Home.tsx:503 +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +Home.tsx:503 Error fetching insights: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async Promise.all (/index 3) + at async fetchAppInsights (Home.tsx:439:85) +fetchAppInsights @ Home.tsx:503 +api.igny8.com/api/v1/writer/content/?site_id=5§or_id=16&page_size=1:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +api.igny8.com/api/v1/writer/tasks/?site_id=5§or_id=16&page_size=1:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +api.igny8.com/api/v1/planner/clusters/?site_id=5§or_id=16&page_size=1:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +api.igny8.com/api/v1/writer/content/?site_id=5§or_id=16&page_size=1:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 + +=============================== + +https://app.igny8.com/linker/content + + + Download the React DevTools for a better development experience: https://react.dev/link/react-devtools +api.igny8.com/api/v1/planner/clusters/?site_id=5§or_id=16&page_size=1:1 Failed to load resource: the server responded with a status of 500 () +api.igny8.com/api/v1/writer/tasks/?site_id=5§or_id=16&page_size=1:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error fetching insights: +fetchAppInsights @ Home.tsx:593 + API Error: Object +fetchAPI @ api.ts:230 + Error fetching insights: +fetchAppInsights @ Home.tsx:593 +api.igny8.com/api/v1/writer/content/?site_id=5§or_id=16&page_size=1:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 +api.igny8.com/api/v1/writer/tasks/?site_id=5§or_id=16&page_size=1:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 +api.igny8.com/api/v1/planner/clusters/?site_id=5§or_id=16&page_size=1:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 +api.igny8.com/api/v1/writer/content/?site_id=5§or_id=16&page_size=1:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 + Error loading content: +(anonymous) @ ContentList.tsx:55 +content/:1 Failed to load resource: the server responded with a status of 500 () + API Error: Object +fetchAPI @ api.ts:230 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: Object +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10', errorData: {…}} +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10', errorData: {…}} +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10', errorData: {…}} +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10', errorData: {…}} +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10', errorData: {…}} +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10', errorData: {…}} +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10', errorData: {…}} +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10', errorData: {…}} +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10', errorData: {…}} +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10', errorData: {…}} +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 +content/:1 Failed to load resource: the server responded with a status of 500 () +api.ts:323 API Error: {status: 500, type: 'HTTP_ERROR', message: 'Internal server error', endpoint: '/v1/writer/content/?site_id=5§or_id=16&page=1&page_size=10', errorData: {…}} +fetchAPI @ api.ts:323 +ContentList.tsx:40 Error loading content: Error: API Error (500): HTTP_ERROR - Internal server error + at fetchAPI (api.ts:332:24) + at async ContentList.tsx:32:20 +(anonymous) @ ContentList.tsx:40 + + + + + diff --git a/backend/igny8_core/ai/functions/generate_image_prompts.py b/backend/igny8_core/ai/functions/generate_image_prompts.py index b77cebe1..817e81dc 100644 --- a/backend/igny8_core/ai/functions/generate_image_prompts.py +++ b/backend/igny8_core/ai/functions/generate_image_prompts.py @@ -207,7 +207,8 @@ class GenerateImagePromptsFunction(BaseAIFunction): soup = BeautifulSoup(html_content, 'html.parser') # Extract title - title = content.title or content.task.title or '' + # Get content title (task field was removed in refactor) + title = content.title or '' # Extract first 1-2 intro paragraphs (skip italic hook if present) paragraphs = soup.find_all('p') diff --git a/backend/igny8_core/business/content/models.py b/backend/igny8_core/business/content/models.py index 5777f60b..d5fa5ff9 100644 --- a/backend/igny8_core/business/content/models.py +++ b/backend/igny8_core/business/content/models.py @@ -22,15 +22,30 @@ class Tasks(SiteSectorBaseModel): limit_choices_to={'sector': models.F('sector')}, help_text="Parent cluster (required)" ) + idea = models.ForeignKey( + 'planner.ContentIdeas', + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name='tasks', + help_text="Optional content idea reference", + db_column='idea_id' + ) content_type = models.CharField( max_length=100, db_index=True, - help_text="Content type: post, page, product, service, category, tag, etc." + help_text="Content type: post, page, product, service, category, tag, etc.", + db_column='entity_type', + blank=True, + null=True ) content_structure = models.CharField( max_length=100, db_index=True, - help_text="Content structure/format: article, listicle, guide, comparison, product_page, etc." + help_text="Content structure/format: article, listicle, guide, comparison, product_page, etc.", + db_column='cluster_role', + blank=True, + null=True ) taxonomy_term = models.ForeignKey( 'ContentTaxonomy', @@ -38,13 +53,13 @@ class Tasks(SiteSectorBaseModel): null=True, blank=True, related_name='tasks', - help_text="Optional taxonomy term assignment" + help_text="Optional taxonomy term assignment", + db_column='taxonomy_id' ) - keywords = models.ManyToManyField( - 'planner.Keywords', + keywords = models.TextField( blank=True, - related_name='tasks', - help_text="Keywords linked to this task" + null=True, + help_text="Comma-separated keywords for this task" ) status = models.CharField(max_length=50, choices=STATUS_CHOICES, default='queued') @@ -70,6 +85,19 @@ class Tasks(SiteSectorBaseModel): return self.title +class ContentTaxonomyRelation(models.Model): + """Through model for Content-Taxonomy many-to-many relationship""" + content = models.ForeignKey('Content', on_delete=models.CASCADE, db_column='content_id') + taxonomy = models.ForeignKey('ContentTaxonomy', on_delete=models.CASCADE, db_column='taxonomy_id') + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + class Meta: + app_label = 'writer' + db_table = 'igny8_content_taxonomy_relations' + unique_together = [['content', 'taxonomy']] + + class Content(SiteSectorBaseModel): """ Content model for AI-generated or WordPress-imported content. @@ -78,7 +106,7 @@ class Content(SiteSectorBaseModel): # Core content fields title = models.CharField(max_length=255, db_index=True) - content_html = models.TextField(help_text="Final HTML content") + content_html = models.TextField(help_text="Final HTML content", db_column='html_content') cluster = models.ForeignKey( 'planner.Clusters', on_delete=models.SET_NULL, @@ -90,26 +118,34 @@ class Content(SiteSectorBaseModel): content_type = models.CharField( max_length=100, db_index=True, - help_text="Content type: post, page, product, service, category, tag, etc." + help_text="Content type: post, page, product, service, category, tag, etc.", + db_column='entity_type', + blank=True, + null=True ) content_structure = models.CharField( max_length=100, db_index=True, - help_text="Content structure/format: article, listicle, guide, comparison, product_page, etc." + help_text="Content structure/format: article, listicle, guide, comparison, product_page, etc.", + db_column='cluster_role', + blank=True, + null=True ) # Taxonomy relationships taxonomy_terms = models.ManyToManyField( 'ContentTaxonomy', + through='ContentTaxonomyRelation', blank=True, related_name='contents', - db_table='igny8_content_taxonomy_relations', help_text="Associated taxonomy terms (categories, tags, attributes)" ) # External platform fields (WordPress integration) external_id = models.CharField(max_length=255, blank=True, null=True, db_index=True, help_text="WordPress/external platform post ID") external_url = models.URLField(blank=True, null=True, help_text="WordPress/external platform URL") + external_type = models.CharField(max_length=100, blank=True, null=True, help_text="WordPress post type (post, page, product, etc.)") + sync_status = models.CharField(max_length=50, blank=True, null=True, help_text="Sync status with WordPress") # Source tracking SOURCE_CHOICES = [ diff --git a/backend/igny8_core/business/content/services/metadata_mapping_service.py b/backend/igny8_core/business/content/services/metadata_mapping_service.py index cbbe22a4..86d6cee5 100644 --- a/backend/igny8_core/business/content/services/metadata_mapping_service.py +++ b/backend/igny8_core/business/content/services/metadata_mapping_service.py @@ -23,62 +23,21 @@ class MetadataMappingService: @transaction.atomic def persist_task_metadata_to_content(self, content: Content) -> None: """ - Persist cluster/taxonomy/attribute mappings from Task to Content. + DEPRECATED: This method is deprecated as Content model no longer has task field. + Metadata is now persisted directly on content model. Args: - content: Content instance with an associated task + content: Content instance """ - if not content.task: - logger.warning(f"Content {content.id} has no associated task, skipping metadata mapping") - return - - task = content.task - - # Stage 3: Persist cluster mapping if task has cluster - if task.cluster: - ContentClusterMap.objects.get_or_create( - content=content, - cluster=task.cluster, - role=task.cluster_role or 'hub', - defaults={ - 'account': content.account, - 'site': content.site, - 'sector': content.sector, - 'source': 'blueprint' if task.idea else 'manual', - 'metadata': {}, - } - ) - logger.info(f"Created cluster mapping for content {content.id} -> cluster {task.cluster.id}") - - # Stage 3: Persist taxonomy mapping if task has taxonomy - if task.taxonomy: - ContentTaxonomyMap.objects.get_or_create( - content=content, - taxonomy=task.taxonomy, - defaults={ - 'account': content.account, - 'site': content.site, - 'sector': content.sector, - 'source': 'blueprint', - 'metadata': {}, - } - ) - logger.info(f"Created taxonomy mapping for content {content.id} -> taxonomy {task.taxonomy.id}") - - # Stage 3: Inherit entity_type from task - if task.entity_type and not content.entity_type: - content.entity_type = task.entity_type - content.save(update_fields=['entity_type']) - logger.info(f"Set entity_type {task.entity_type} for content {content.id}") - - # Stage 3: Extract attributes from task metadata if available - # This can be extended to parse task.description or task.metadata for attributes - # For now, we'll rely on explicit attribute data in future enhancements + logger.warning(f"[persist_task_metadata_to_content] Deprecated method called for content {content.id}") + logger.warning(f"Content model no longer has task field - metadata should be set directly on content") + return @transaction.atomic def backfill_content_metadata(self, content: Content) -> None: """ Backfill metadata mappings for existing content that may be missing mappings. + Note: task field was removed from Content model - only infers from content metadata. Args: content: Content instance to backfill @@ -87,13 +46,24 @@ class MetadataMappingService: if ContentClusterMap.objects.filter(content=content).exists(): return - # Try to infer from task - if content.task: - self.persist_task_metadata_to_content(content) + # Try to infer from content metadata or cluster field + if hasattr(content, 'cluster') and content.cluster: + ContentClusterMap.objects.get_or_create( + content=content, + cluster=content.cluster, + role='hub', # Default + defaults={ + 'account': content.account, + 'site': content.site, + 'sector': content.sector, + 'source': 'manual', + 'metadata': {}, + } + ) return - # Try to infer from content metadata - if content.metadata: + # Fallback: Try to infer from content metadata + if hasattr(content, 'metadata') and content.metadata: cluster_id = content.metadata.get('cluster_id') if cluster_id: from igny8_core.business.planning.models import Clusters diff --git a/backend/igny8_core/business/content/services/validation_service.py b/backend/igny8_core/business/content/services/validation_service.py index 92086dc4..ccce86e1 100644 --- a/backend/igny8_core/business/content/services/validation_service.py +++ b/backend/igny8_core/business/content/services/validation_service.py @@ -37,20 +37,20 @@ class ContentValidationService: }) # Stage 3: Validate entity_type is set - if not task.entity_type: + if not task.content_type: errors.append({ - 'field': 'entity_type', - 'code': 'missing_entity_type', - 'message': 'Task must have an entity type specified', + 'field': 'content_type', + 'code': 'missing_content_type', + 'message': 'Task must have a content type specified', }) # Stage 3: Validate taxonomy for product/service entities - if task.entity_type in ['product', 'service']: - if not task.taxonomy: + if task.content_type in ['product', 'service']: + if not task.taxonomy_term: errors.append({ 'field': 'taxonomy', 'code': 'missing_taxonomy', - 'message': f'{task.entity_type.title()} tasks require a taxonomy association', + 'message': f'{task.content_type.title()} tasks require a taxonomy association', }) return errors @@ -67,12 +67,12 @@ class ContentValidationService: """ errors = [] - # Stage 3: Validate entity_type - if not content.entity_type: + # Stage 3: Validate content_type + if not content.content_type: errors.append({ - 'field': 'entity_type', - 'code': 'missing_entity_type', - 'message': 'Content must have an entity type specified', + 'field': 'content_type', + 'code': 'missing_content_type', + 'message': 'Content must have a content type specified', }) # Stage 3: Validate cluster mapping exists for IGNY8 content @@ -86,30 +86,20 @@ class ContentValidationService: }) # Stage 3: Validate taxonomy for product/service content - if content.entity_type in ['product', 'service']: - from igny8_core.business.content.models import ContentTaxonomyMap - if not ContentTaxonomyMap.objects.filter(content=content).exists(): + if content.content_type in ['product', 'service']: + # Check if content has taxonomy terms assigned + if not content.taxonomy_terms.exists(): errors.append({ 'field': 'taxonomy_mapping', 'code': 'missing_taxonomy_mapping', - 'message': f'{content.entity_type.title()} content requires a taxonomy mapping', + 'message': f'{content.content_type.title()} content requires a taxonomy mapping', }) # Stage 3: Validate required attributes for products - if content.entity_type == 'product': - from igny8_core.business.content.models import ContentAttributeMap - required_attrs = ['price', 'sku', 'category'] - existing_attrs = ContentAttributeMap.objects.filter( - content=content, - name__in=required_attrs - ).values_list('name', flat=True) - missing_attrs = set(required_attrs) - set(existing_attrs) - if missing_attrs: - errors.append({ - 'field': 'attributes', - 'code': 'missing_attributes', - 'message': f'Product content requires attributes: {", ".join(missing_attrs)}', - }) + if content.content_type == 'product': + # Product validation - currently simplified in Stage 1 + # TODO: Re-enable attribute validation when product attributes are implemented + pass return errors @@ -136,9 +126,9 @@ class ContentValidationService: 'message': 'Content must have a title before publishing', }) - if not content.html_content or len(content.html_content.strip()) < 100: + if not content.content_html or len(content.content_html.strip()) < 100: errors.append({ - 'field': 'html_content', + 'field': 'content_html', 'code': 'insufficient_content', 'message': 'Content must have at least 100 characters before publishing', }) @@ -157,9 +147,9 @@ class ContentValidationService: """ errors = [] - if task.entity_type == 'product': + if task.content_type == 'product': # Products should have taxonomy and cluster - if not task.taxonomy: + if not task.taxonomy_term: errors.append({ 'field': 'taxonomy', 'code': 'missing_taxonomy', diff --git a/backend/igny8_core/modules/integration/views.py b/backend/igny8_core/modules/integration/views.py index 6266e323..a48bad7a 100644 --- a/backend/igny8_core/modules/integration/views.py +++ b/backend/igny8_core/modules/integration/views.py @@ -348,19 +348,19 @@ class IntegrationViewSet(SiteSectorModelViewSet): # Build response with synced counts post_types_data = {} for wp_type, type_config in content_types.get('post_types', {}).items(): - # Map WP type to entity_type - entity_type_map = { + # Map WP type to content_type + content_type_map = { 'post': 'post', 'page': 'page', 'product': 'product', 'service': 'service', } - entity_type = entity_type_map.get(wp_type, 'post') + content_type = content_type_map.get(wp_type, 'post') # Count synced content synced_count = Content.objects.filter( site=site, - entity_type=entity_type, + content_type=content_type, external_type=wp_type, sync_status__in=['imported', 'synced'] ).count() @@ -379,8 +379,7 @@ class IntegrationViewSet(SiteSectorModelViewSet): # Count synced taxonomies synced_count = ContentTaxonomy.objects.filter( site=site, - external_taxonomy=wp_tax, - sync_status__in=['imported', 'synced'] + external_taxonomy=wp_tax ).count() taxonomies_data[wp_tax] = { diff --git a/backend/igny8_core/modules/planner/cluster_serializers.py b/backend/igny8_core/modules/planner/cluster_serializers.py index bf9607a2..558da254 100644 --- a/backend/igny8_core/modules/planner/cluster_serializers.py +++ b/backend/igny8_core/modules/planner/cluster_serializers.py @@ -102,13 +102,14 @@ class ClusterSerializer(serializers.ModelSerializer): return ContentIdeas.objects.filter(keyword_cluster_id=obj.id).count() def get_content_count(self, obj): - """Count generated content items linked to this cluster via tasks""" + """Count generated content items linked to this cluster""" if hasattr(obj, '_content_count'): return obj._content_count from igny8_core.modules.writer.models import Content - return Content.objects.filter(task__cluster_id=obj.id).count() + # Content links directly to clusters now (task field was removed in refactor) + return Content.objects.filter(cluster_id=obj.id).count() @classmethod def prefetch_keyword_stats(cls, clusters): @@ -166,16 +167,16 @@ class ClusterSerializer(serializers.ModelSerializer): ) idea_stats = {item['keyword_cluster_id']: item['count'] for item in idea_counts} - # Prefetch content counts (through writer.Tasks -> Content) + # Prefetch content counts (Content links directly to Clusters now) from igny8_core.modules.writer.models import Content content_counts = ( Content.objects - .filter(task__cluster_id__in=cluster_ids) - .values('task__cluster_id') + .filter(cluster_id__in=cluster_ids) + .values('cluster_id') .annotate(count=Count('id')) ) - content_stats = {item['task__cluster_id']: item['count'] for item in content_counts} + content_stats = {item['cluster_id']: item['count'] for item in content_counts} # Attach stats to each cluster object for cluster in clusters: diff --git a/backend/igny8_core/modules/writer/admin.py b/backend/igny8_core/modules/writer/admin.py index 1fc3d1b8..bfa8d8f6 100644 --- a/backend/igny8_core/modules/writer/admin.py +++ b/backend/igny8_core/modules/writer/admin.py @@ -102,10 +102,6 @@ class ContentAdmin(SiteSectorAdminMixin, admin.ModelAdmin): ('Content', { 'fields': ('content_html',) }), - ('Taxonomy', { - 'fields': ('taxonomy_terms',), - 'description': 'Categories, tags, and other taxonomy terms' - }), ('WordPress Sync', { 'fields': ('external_id', 'external_url'), 'classes': ('collapse',) diff --git a/backend/igny8_core/modules/writer/views.py b/backend/igny8_core/modules/writer/views.py index 2fc71e40..40eec476 100644 --- a/backend/igny8_core/modules/writer/views.py +++ b/backend/igny8_core/modules/writer/views.py @@ -488,14 +488,12 @@ class ImagesViewSet(SiteSectorModelViewSet): # Update by content_id if provided, otherwise by image IDs if content_id: try: - # Get the content object to also update images linked via task + # Get the content object to also update images linked directly to content content = Content.objects.get(id=content_id) - # Update images linked directly to content OR via task (same logic as content_images endpoint) - # This ensures we update all images: featured + 1-6 in-article images - updated_count = queryset.filter( - Q(content=content) | Q(task=content.task) - ).update(status=status_value) + # Update images linked directly to content (all images: featured + in-article) + # Note: task field was removed in refactor - images now link directly to content + updated_count = queryset.filter(content=content).update(status=status_value) except Content.DoesNotExist: return error_response( error='Content not found', @@ -670,8 +668,8 @@ class ImagesViewSet(SiteSectorModelViewSet): 'validation_errors': errors, 'publish_errors': publish_errors, 'metadata': { - 'has_entity_type': bool(content.entity_type), - 'entity_type': content.entity_type, + 'has_entity_type': bool(content.content_type), + 'entity_type': content.content_type, 'has_cluster_mapping': self._has_cluster_mapping(content), 'has_taxonomy_mapping': self._has_taxonomy_mapping(content), } @@ -691,9 +689,9 @@ class ImagesViewSet(SiteSectorModelViewSet): validation_service = ContentValidationService() # Persist metadata mappings if task exists - if content.task: - mapping_service = MetadataMappingService() - mapping_service.persist_task_metadata_to_content(content) + # Metadata is now persisted directly on content - no task linkage needed + # mapping_service = MetadataMappingService() # DEPRECATED + # mapping_service.persist_task_metadata_to_content(content) # DEPRECATED errors = validation_service.validate_for_publish(content) @@ -970,8 +968,8 @@ class ContentViewSet(SiteSectorModelViewSet): 'validation_errors': errors, 'publish_errors': publish_errors, 'metadata': { - 'has_entity_type': bool(content.entity_type), - 'entity_type': content.entity_type, + 'has_entity_type': bool(content.content_type), + 'entity_type': content.content_type, 'has_cluster_mapping': self._has_cluster_mapping(content), 'has_taxonomy_mapping': self._has_taxonomy_mapping(content), } @@ -991,9 +989,9 @@ class ContentViewSet(SiteSectorModelViewSet): validation_service = ContentValidationService() # Persist metadata mappings if task exists - if content.task: - mapping_service = MetadataMappingService() - mapping_service.persist_task_metadata_to_content(content) + # Metadata is now persisted directly on content - no task linkage needed + # mapping_service = MetadataMappingService() # DEPRECATED + # mapping_service.persist_task_metadata_to_content(content) # DEPRECATED errors = validation_service.validate_for_publish(content) @@ -1121,8 +1119,8 @@ class ContentViewSet(SiteSectorModelViewSet): 'validation_errors': errors, 'publish_errors': publish_errors, 'metadata': { - 'has_entity_type': bool(content.entity_type), - 'entity_type': content.entity_type, + 'has_entity_type': bool(content.content_type), + 'entity_type': content.content_type, 'has_cluster_mapping': self._has_cluster_mapping(content), 'has_taxonomy_mapping': self._has_taxonomy_mapping(content), } @@ -1142,9 +1140,9 @@ class ContentViewSet(SiteSectorModelViewSet): validation_service = ContentValidationService() # Persist metadata mappings if task exists - if content.task: - mapping_service = MetadataMappingService() - mapping_service.persist_task_metadata_to_content(content) + # Metadata is now persisted directly on content - no task linkage needed + # mapping_service = MetadataMappingService() # DEPRECATED + # mapping_service.persist_task_metadata_to_content(content) # DEPRECATED errors = validation_service.validate_for_publish(content) @@ -1272,8 +1270,8 @@ class ContentViewSet(SiteSectorModelViewSet): 'validation_errors': errors, 'publish_errors': publish_errors, 'metadata': { - 'has_entity_type': bool(content.entity_type), - 'entity_type': content.entity_type, + 'has_entity_type': bool(content.content_type), + 'entity_type': content.content_type, 'has_cluster_mapping': self._has_cluster_mapping(content), 'has_taxonomy_mapping': self._has_taxonomy_mapping(content), } @@ -1293,9 +1291,9 @@ class ContentViewSet(SiteSectorModelViewSet): validation_service = ContentValidationService() # Persist metadata mappings if task exists - if content.task: - mapping_service = MetadataMappingService() - mapping_service.persist_task_metadata_to_content(content) + # Metadata is now persisted directly on content - no task linkage needed + # mapping_service = MetadataMappingService() # DEPRECATED + # mapping_service.persist_task_metadata_to_content(content) # DEPRECATED errors = validation_service.validate_for_publish(content) @@ -1422,8 +1420,8 @@ class ContentViewSet(SiteSectorModelViewSet): 'validation_errors': errors, 'publish_errors': publish_errors, 'metadata': { - 'has_entity_type': bool(content.entity_type), - 'entity_type': content.entity_type, + 'has_entity_type': bool(content.content_type), + 'entity_type': content.content_type, 'has_cluster_mapping': self._has_cluster_mapping(content), 'has_taxonomy_mapping': self._has_taxonomy_mapping(content), } @@ -1443,9 +1441,9 @@ class ContentViewSet(SiteSectorModelViewSet): validation_service = ContentValidationService() # Persist metadata mappings if task exists - if content.task: - mapping_service = MetadataMappingService() - mapping_service.persist_task_metadata_to_content(content) + # Metadata is now persisted directly on content - no task linkage needed + # mapping_service = MetadataMappingService() # DEPRECATED + # mapping_service.persist_task_metadata_to_content(content) # DEPRECATED errors = validation_service.validate_for_publish(content) @@ -1466,7 +1464,7 @@ class ContentViewSet(SiteSectorModelViewSet): def _has_taxonomy_mapping(self, content): """Helper to check if content has taxonomy mapping""" # Check new M2M relationship - return content.taxonomies.exists() + return content.taxonomy_terms.exists() @extend_schema_view( diff --git a/backend/igny8_core/modules/writer/views.py.bak b/backend/igny8_core/modules/writer/views.py.bak new file mode 100644 index 00000000..d57e9548 --- /dev/null +++ b/backend/igny8_core/modules/writer/views.py.bak @@ -0,0 +1,1597 @@ +from rest_framework import viewsets, filters, status +from rest_framework.decorators import action +from rest_framework.response import Response +from django_filters.rest_framework import DjangoFilterBackend +from django.db import transaction, models +from django.db.models import Q +from drf_spectacular.utils import extend_schema, extend_schema_view +from igny8_core.api.base import SiteSectorModelViewSet +from igny8_core.api.pagination import CustomPageNumberPagination +from igny8_core.api.response import success_response, error_response +from igny8_core.api.throttles import DebugScopedRateThrottle +from igny8_core.api.permissions import IsAuthenticatedAndActive, IsViewerOrAbove, IsEditorOrAbove +from .models import Tasks, Images, Content +from .serializers import ( + TasksSerializer, + ImagesSerializer, + ContentSerializer, + ContentTaxonomySerializer, +) +from igny8_core.business.content.models import ContentTaxonomy # ContentAttribute model exists but serializer removed in Stage 1 +from igny8_core.business.content.services.content_generation_service import ContentGenerationService +from igny8_core.business.content.services.validation_service import ContentValidationService +from igny8_core.business.content.services.metadata_mapping_service import MetadataMappingService +from igny8_core.business.billing.exceptions import InsufficientCreditsError + + + +@extend_schema_view( + list=extend_schema(tags=['Writer']), + create=extend_schema(tags=['Writer']), + retrieve=extend_schema(tags=['Writer']), + update=extend_schema(tags=['Writer']), + partial_update=extend_schema(tags=['Writer']), + destroy=extend_schema(tags=['Writer']), +) +class TasksViewSet(SiteSectorModelViewSet): + """ + ViewSet for managing tasks with CRUD operations + Unified API Standard v1.0 compliant + Stage 1 Refactored - removed deprecated filters + """ + queryset = Tasks.objects.select_related('cluster', 'site', 'sector') + serializer_class = TasksSerializer + permission_classes = [IsAuthenticatedAndActive, IsViewerOrAbove] + pagination_class = CustomPageNumberPagination # Explicitly use custom pagination + throttle_scope = 'writer' + throttle_classes = [DebugScopedRateThrottle] + + # DRF filtering configuration + filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] + + # Search configuration + search_fields = ['title', 'keywords'] + + # Ordering configuration + ordering_fields = ['title', 'created_at', 'status'] + ordering = ['-created_at'] # Default ordering (newest first) + + # Filter configuration - Stage 1: removed entity_type, cluster_role + filterset_fields = ['status', 'cluster_id', 'content_type', 'content_structure'] + + def perform_create(self, serializer): + """Require explicit site_id and sector_id - no defaults.""" + user = getattr(self.request, 'user', None) + + try: + query_params = getattr(self.request, 'query_params', None) + if query_params is None: + query_params = getattr(self.request, 'GET', {}) + except AttributeError: + query_params = {} + + site_id = serializer.validated_data.get('site_id') or query_params.get('site_id') + sector_id = serializer.validated_data.get('sector_id') or query_params.get('sector_id') + + from igny8_core.auth.models import Site, Sector + from rest_framework.exceptions import ValidationError + + # Site ID is REQUIRED + if not site_id: + raise ValidationError("site_id is required. Please select a site.") + + try: + site = Site.objects.get(id=site_id) + except Site.DoesNotExist: + raise ValidationError(f"Site with id {site_id} does not exist") + + # Sector ID is REQUIRED + if not sector_id: + raise ValidationError("sector_id is required. Please select a sector.") + + try: + sector = Sector.objects.get(id=sector_id) + if sector.site_id != site_id: + raise ValidationError(f"Sector does not belong to the selected site") + except Sector.DoesNotExist: + raise ValidationError(f"Sector with id {sector_id} does not exist") + + serializer.validated_data.pop('site_id', None) + serializer.validated_data.pop('sector_id', None) + + account = getattr(self.request, 'account', None) + if not account and user and user.is_authenticated and user.account: + account = user.account + if not account: + account = site.account + + serializer.save(account=account, site=site, sector=sector) + + @action(detail=False, methods=['POST'], url_path='bulk_delete', url_name='bulk_delete') + def bulk_delete(self, request): + """Bulk delete tasks""" + ids = request.data.get('ids', []) + if not ids: + return error_response( + error='No IDs provided', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + queryset = self.get_queryset() + deleted_count, _ = queryset.filter(id__in=ids).delete() + + return success_response(data={'deleted_count': deleted_count}, request=request) + + @action(detail=False, methods=['post'], url_path='bulk_update', url_name='bulk_update') + def bulk_update(self, request): + """Bulk update task status""" + ids = request.data.get('ids', []) + status_value = request.data.get('status') + + if not ids: + return error_response( + error='No IDs provided', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + if not status_value: + return error_response( + error='No status provided', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + queryset = self.get_queryset() + updated_count = queryset.filter(id__in=ids).update(status=status_value) + + return success_response(data={'updated_count': updated_count}, request=request) + + @action(detail=False, methods=['post'], url_path='auto_generate_content', url_name='auto_generate_content') + def auto_generate_content(self, request): + """Auto-generate content for tasks using ContentGenerationService""" + import logging + + logger = logging.getLogger(__name__) + + try: + ids = request.data.get('ids', []) + if not ids: + return error_response( + error='No IDs provided', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + if len(ids) > 10: + return error_response( + error='Maximum 10 tasks allowed for content generation', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + # Get account + account = getattr(request, 'account', None) + if not account: + return error_response( + error='Account is required', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + # Validate task IDs exist + queryset = self.get_queryset() + existing_tasks = queryset.filter(id__in=ids, account=account) + existing_count = existing_tasks.count() + + if existing_count == 0: + return error_response( + error=f'No tasks found for the provided IDs: {ids}', + status_code=status.HTTP_404_NOT_FOUND, + request=request + ) + + # Use service to generate content + service = ContentGenerationService() + try: + result = service.generate_content(ids, account) + + if result.get('success'): + if 'task_id' in result: + # Async task queued + return success_response( + data={'task_id': result['task_id']}, + message=result.get('message', 'Content generation started'), + request=request + ) + else: + # Synchronous execution + return success_response( + data=result, + message='Content generated successfully', + request=request + ) + else: + return error_response( + error=result.get('error', 'Content generation failed'), + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + except InsufficientCreditsError as e: + return error_response( + error=str(e), + status_code=status.HTTP_402_PAYMENT_REQUIRED, + request=request + ) + except Exception as e: + logger.error(f"Error in auto_generate_content: {str(e)}", exc_info=True) + return error_response( + error=f'Content generation failed: {str(e)}', + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + + except Exception as e: + logger.error(f"Unexpected error in auto_generate_content: {str(e)}", exc_info=True) + return error_response( + error=f'Unexpected error: {str(e)}', + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + + +@extend_schema_view( + list=extend_schema(tags=['Writer']), + create=extend_schema(tags=['Writer']), + retrieve=extend_schema(tags=['Writer']), + update=extend_schema(tags=['Writer']), + partial_update=extend_schema(tags=['Writer']), + destroy=extend_schema(tags=['Writer']), +) +class ImagesViewSet(SiteSectorModelViewSet): + """ + ViewSet for managing content images + Unified API Standard v1.0 compliant + """ + queryset = Images.objects.all() + serializer_class = ImagesSerializer + permission_classes = [IsAuthenticatedAndActive, IsViewerOrAbove] + pagination_class = CustomPageNumberPagination + throttle_scope = 'writer' + throttle_classes = [DebugScopedRateThrottle] + + filter_backends = [DjangoFilterBackend, filters.OrderingFilter] + ordering_fields = ['created_at', 'position', 'id'] + ordering = ['-id'] # Sort by ID descending (newest first) + filterset_fields = ['task_id', 'content_id', 'image_type', 'status'] + + def perform_create(self, serializer): + """Override to automatically set account, site, and sector""" + from rest_framework.exceptions import ValidationError + + # Get site and sector from request (set by middleware) or user's active context + site = getattr(self.request, 'site', None) + sector = getattr(self.request, 'sector', None) + + if not site: + # Fallback to user's active site if not set by middleware + user = getattr(self.request, 'user', None) + if user and user.is_authenticated and hasattr(user, 'active_site'): + site = user.active_site + + if not sector and site: + # Fallback to default sector for the site if not set by middleware + from igny8_core.auth.models import Sector + sector = site.sectors.filter(is_default=True).first() + + # Site and sector are required - raise ValidationError if not available + # Use dict format for ValidationError to ensure proper error structure + if not site: + raise ValidationError({"site": ["Site is required for image creation. Please select a site."]}) + if not sector: + raise ValidationError({"sector": ["Sector is required for image creation. Please select a sector."]}) + + # Add site and sector to validated_data so base class can validate access + serializer.validated_data['site'] = site + serializer.validated_data['sector'] = sector + + # Call parent to set account and validate access + super().perform_create(serializer) + + @action(detail=True, methods=['get'], url_path='file', url_name='image_file') + def serve_image_file(self, request, pk=None): + """ + Serve image file from local path via URL + GET /api/v1/writer/images/{id}/file/ + """ + import os + from django.http import FileResponse, Http404 + from django.conf import settings + + try: + # Get image directly without account filtering for file serving + # This allows public access to image files + try: + image = Images.objects.get(pk=pk) + except Images.DoesNotExist: + return error_response( + error='Image not found', + status_code=status.HTTP_404_NOT_FOUND, + request=request + ) + + # Check if image has a local path + if not image.image_path: + return error_response( + error='No local file path available for this image', + status_code=status.HTTP_404_NOT_FOUND, + request=request + ) + + file_path = image.image_path + + # Verify file exists at the saved path + if not os.path.exists(file_path): + logger.error(f"[serve_image_file] Image {pk} - File not found at saved path: {file_path}") + return error_response( + error=f'Image file not found at: {file_path}', + status_code=status.HTTP_404_NOT_FOUND, + request=request + ) + + # Check if file is readable + if not os.access(file_path, os.R_OK): + return error_response( + error='Image file is not readable', + status_code=status.HTTP_403_FORBIDDEN, + request=request + ) + + # Determine content type from file extension + import mimetypes + content_type, _ = mimetypes.guess_type(file_path) + if not content_type: + content_type = 'image/png' # Default to PNG + + # Serve the file + try: + return FileResponse( + open(file_path, 'rb'), + content_type=content_type, + filename=os.path.basename(file_path) + ) + except Exception as e: + return error_response( + error=f'Failed to serve file: {str(e)}', + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + + except Images.DoesNotExist: + return error_response( + error='Image not found', + status_code=status.HTTP_404_NOT_FOUND, + request=request + ) + except Exception as e: + import logging + logger = logging.getLogger(__name__) + logger.error(f"Error serving image file: {str(e)}", exc_info=True) + return error_response( + error=f'Failed to serve image: {str(e)}', + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + + @action(detail=False, methods=['post'], url_path='auto_generate', url_name='auto_generate_images') + def auto_generate_images(self, request): + """Auto-generate images for tasks using AI""" + task_ids = request.data.get('task_ids', []) + if not task_ids: + return error_response( + error='No task IDs provided', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + if len(task_ids) > 10: + return error_response( + error='Maximum 10 tasks allowed for image generation', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + # Get account + account = getattr(request, 'account', None) + account_id = account.id if account else None + + # Try to queue Celery task, fall back to synchronous if Celery not available + try: + from igny8_core.ai.tasks import run_ai_task + from kombu.exceptions import OperationalError as KombuOperationalError + + if hasattr(run_ai_task, 'delay'): + # Celery is available - queue async task + task = run_ai_task.delay( + function_name='generate_images', + payload={'ids': task_ids}, + account_id=account_id + ) + return success_response( + data={'task_id': str(task.id)}, + message='Image generation started', + request=request + ) + else: + # Celery not available - execute synchronously + result = run_ai_task( + function_name='generate_images', + payload={'ids': task_ids}, + account_id=account_id + ) + if result.get('success'): + return success_response( + data={'images_created': result.get('count', 0)}, + message=result.get('message', 'Image generation completed'), + request=request + ) + else: + return error_response( + error=result.get('error', 'Image generation failed'), + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + except KombuOperationalError as e: + return error_response( + error='Task queue unavailable. Please try again.', + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + request=request + ) + except ImportError: + # Tasks module not available + return error_response( + error='Image generation task not available', + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + request=request + ) + except Exception as e: + import logging + logger = logging.getLogger(__name__) + logger.error(f"Error queuing image generation task: {str(e)}", exc_info=True) + return error_response( + error=f'Failed to start image generation: {str(e)}', + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + + @action(detail=False, methods=['post'], url_path='bulk_update', url_name='bulk_update') + def bulk_update(self, request): + """Bulk update image status by content_id or image IDs + Updates all images for a content record (featured + 1-6 in-article images) + """ + from django.db.models import Q + from .models import Content + + content_id = request.data.get('content_id') + image_ids = request.data.get('ids', []) + status_value = request.data.get('status') + + if not status_value: + return error_response( + error='No status provided', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + queryset = self.get_queryset() + + # Update by content_id if provided, otherwise by image IDs + if content_id: + try: + # Get the content object to also update images linked directly to content + content = Content.objects.get(id=content_id) + + # Update images linked directly to content (all images: featured + in-article) + # Note: task field was removed in refactor - images now link directly to content + updated_count = queryset.filter(content=content).update(status=status_value) + except Content.DoesNotExist: + return error_response( + error='Content not found', + status_code=status.HTTP_404_NOT_FOUND, + request=request + ) + elif image_ids: + updated_count = queryset.filter(id__in=image_ids).update(status=status_value) + else: + return error_response( + error='Either content_id or ids must be provided', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + return success_response(data={'updated_count': updated_count}, request=request) + + @action(detail=False, methods=['get'], url_path='content_images', url_name='content_images') + def content_images(self, request): + """Get images grouped by content - one row per content with featured and in-article images""" + from .serializers import ContentImagesGroupSerializer, ContentImageSerializer + + account = getattr(request, 'account', None) + + # Get site_id and sector_id from query parameters + site_id = request.query_params.get('site_id') + sector_id = request.query_params.get('sector_id') + + # Get all content that has images (either directly or via task) + # First, get content with direct image links + queryset = Content.objects.filter(images__isnull=False) + if account: + queryset = queryset.filter(account=account) + + # Apply site/sector filtering if provided + if site_id: + try: + queryset = queryset.filter(site_id=int(site_id)) + except (ValueError, TypeError): + pass + + if sector_id: + try: + queryset = queryset.filter(sector_id=int(sector_id)) + except (ValueError, TypeError): + pass + + # Task field removed in Stage 1 - images are now only linked to content directly + # All images must be linked via content, not task + + # Build grouped response + grouped_data = [] + content_ids = set(queryset.values_list('id', flat=True).distinct()) + + for content_id in content_ids: + try: + content = Content.objects.get(id=content_id) + + # Get images linked directly to content + content_images = Images.objects.filter(content=content).order_by('position') + + # Get featured image + featured_image = content_images.filter(image_type='featured').first() + + # Get in-article images (sorted by position) + in_article_images = list(content_images.filter(image_type='in_article').order_by('position')) + + # Determine overall status + all_images = list(content_images) + if not all_images: + overall_status = 'pending' + elif all(img.status == 'generated' for img in all_images): + overall_status = 'complete' + elif any(img.status == 'failed' for img in all_images): + overall_status = 'failed' + elif any(img.status == 'generated' for img in all_images): + overall_status = 'partial' + else: + overall_status = 'pending' + + # Create serializer instances with request context for proper URL generation + featured_serializer = ContentImageSerializer(featured_image, context={'request': request}) if featured_image else None + in_article_serializers = [ContentImageSerializer(img, context={'request': request}) for img in in_article_images] + + grouped_data.append({ + 'content_id': content.id, + 'content_title': content.title or content.meta_title or f"Content #{content.id}", + 'featured_image': featured_serializer.data if featured_serializer else None, + 'in_article_images': [s.data for s in in_article_serializers], + 'overall_status': overall_status, + }) + except Content.DoesNotExist: + continue + + # Sort by content title + grouped_data.sort(key=lambda x: x['content_title']) + + return success_response( + data={ + 'count': len(grouped_data), + 'results': grouped_data + }, + request=request + ) + + @action(detail=False, methods=['post'], url_path='generate_images', url_name='generate_images') + def generate_images(self, request): + """Generate images from prompts - queues Celery task for sequential processing""" + from igny8_core.ai.tasks import process_image_generation_queue + + account = getattr(request, 'account', None) + image_ids = request.data.get('ids', []) + content_id = request.data.get('content_id') + + if not image_ids: + return error_response( + error='No image IDs provided', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + account_id = account.id if account else None + + # Queue Celery task + try: + if hasattr(process_image_generation_queue, 'delay'): + task = process_image_generation_queue.delay( + image_ids=image_ids, + account_id=account_id, + content_id=content_id + ) + return success_response( + data={'task_id': str(task.id)}, + message='Image generation started', + request=request + ) + else: + # Fallback to synchronous execution (for testing) + result = process_image_generation_queue( + image_ids=image_ids, + account_id=account_id, + content_id=content_id + ) + return success_response(data=result, request=request) + except Exception as e: + logger.error(f"[generate_images] Error: {str(e)}", exc_info=True) + return error_response( + error=str(e), + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + + @action(detail=True, methods=['get'], url_path='validation', url_name='validation') + def validation(self, request, pk=None): + """ + Stage 3: Get validation checklist for content. + + GET /api/v1/writer/content/{id}/validation/ + Returns aggregated validation checklist for Writer UI. + """ + content = self.get_object() + validation_service = ContentValidationService() + + errors = validation_service.validate_content(content) + publish_errors = validation_service.validate_for_publish(content) + + return success_response( + data={ + 'content_id': content.id, + 'is_valid': len(errors) == 0, + 'ready_to_publish': len(publish_errors) == 0, + 'validation_errors': errors, + 'publish_errors': publish_errors, + 'metadata': { + 'has_entity_type': bool(content.entity_type), + 'entity_type': content.entity_type, + 'has_cluster_mapping': self._has_cluster_mapping(content), + 'has_taxonomy_mapping': self._has_taxonomy_mapping(content), + } + }, + request=request + ) + + @action(detail=True, methods=['post'], url_path='validate', url_name='validate') + def validate(self, request, pk=None): + """ + Stage 3: Re-run validators and return actionable errors. + + POST /api/v1/writer/content/{id}/validate/ + Re-validates content and returns structured errors. + """ + content = self.get_object() + validation_service = ContentValidationService() + + # Persist metadata mappings if task exists + if content.task: + mapping_service = MetadataMappingService() + mapping_service.persist_task_metadata_to_content(content) + + errors = validation_service.validate_for_publish(content) + + return success_response( + data={ + 'content_id': content.id, + 'is_valid': len(errors) == 0, + 'errors': errors, + }, + request=request + ) + + def _has_cluster_mapping(self, content): + """Helper to check if content has cluster mapping""" + from igny8_core.business.content.models import ContentClusterMap + return ContentClusterMap.objects.filter(content=content).exists() + + def _has_taxonomy_mapping(self, content): + """Helper to check if content has taxonomy mapping""" + from igny8_core.business.content.models import ContentTaxonomyMap + return ContentTaxonomyMap.objects.filter(content=content).exists() + +@extend_schema_view( + list=extend_schema(tags=['Writer']), + create=extend_schema(tags=['Writer']), + retrieve=extend_schema(tags=['Writer']), + update=extend_schema(tags=['Writer']), + partial_update=extend_schema(tags=['Writer']), + destroy=extend_schema(tags=['Writer']), +) +class ContentViewSet(SiteSectorModelViewSet): + """ + ViewSet for managing content with new unified structure + Unified API Standard v1.0 compliant + Stage 1 Refactored - removed deprecated fields + """ + queryset = Content.objects.select_related('cluster', 'site', 'sector').prefetch_related('taxonomy_terms') + serializer_class = ContentSerializer + permission_classes = [IsAuthenticatedAndActive, IsViewerOrAbove] + pagination_class = CustomPageNumberPagination + throttle_scope = 'writer' + throttle_classes = [DebugScopedRateThrottle] + + filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] + search_fields = ['title', 'content_html', 'external_url'] + ordering_fields = ['created_at', 'updated_at', 'status'] + ordering = ['-created_at'] + # Stage 1: removed task_id, entity_type, content_format, cluster_role, sync_status, external_type + filterset_fields = [ + 'cluster_id', + 'status', + 'content_type', + 'content_structure', + 'source', + ] + + def perform_create(self, serializer): + """Override to automatically set account""" + account = getattr(self.request, 'account', None) + if account: + serializer.save(account=account) + else: + serializer.save() + + @action(detail=True, methods=['post'], url_path='publish', url_name='publish', permission_classes=[IsAuthenticatedAndActive, IsEditorOrAbove]) + def publish(self, request, pk=None): + """ + STAGE 3: Publish content to WordPress site. + Prevents duplicate publishing and updates external_id/external_url. + + POST /api/v1/writer/content/{id}/publish/ + { + "site_id": 1, // Optional - defaults to content's site + "status": "publish" // Optional - draft or publish + } + """ + from igny8_core.auth.models import Site + from igny8_core.business.publishing.services.adapters.wordpress_adapter import WordPressAdapter + + content = self.get_object() + + # STAGE 3: Prevent duplicate publishing + if content.external_id: + return error_response( + error='Content already published. Use WordPress to update or unpublish first.', + status_code=status.HTTP_400_BAD_REQUEST, + request=request, + errors={'external_id': [f'Already published with ID: {content.external_id}']} + ) + + # Get site (use content's site if not specified) + site_id = request.data.get('site_id') or content.site_id + if not site_id: + return error_response( + error='site_id is required or content must have a site', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + try: + site = Site.objects.get(id=site_id) + except Site.DoesNotExist: + return error_response( + error=f'Site with id {site_id} does not exist', + status_code=status.HTTP_404_NOT_FOUND, + request=request + ) + + # Get WordPress credentials from site metadata + wp_credentials = site.metadata.get('wordpress', {}) if site.metadata else {} + wp_url = wp_credentials.get('url') or site.url + wp_username = wp_credentials.get('username') + wp_app_password = wp_credentials.get('app_password') + + if not wp_username or not wp_app_password: + return error_response( + error='WordPress credentials not configured for this site', + status_code=status.HTTP_400_BAD_REQUEST, + request=request, + errors={'credentials': ['Missing WordPress username or app password in site settings']} + ) + + # Use WordPress adapter to publish + adapter = WordPressAdapter() + wp_status = request.data.get('status', 'publish') # draft or publish + + result = adapter.publish( + content=content, + destination_config={ + 'site_url': wp_url, + 'username': wp_username, + 'app_password': wp_app_password, + 'status': wp_status, + } + ) + + if result.get('success'): + # STAGE 3: Update content with external references + content.external_id = result.get('external_id') + content.external_url = result.get('url') + content.status = 'published' + content.save(update_fields=['external_id', 'external_url', 'status', 'updated_at']) + + return success_response( + data={ + 'content_id': content.id, + 'status': content.status, + 'external_id': content.external_id, + 'external_url': content.external_url, + }, + message='Content published to WordPress successfully', + request=request + ) + else: + return error_response( + error=f"Failed to publish to WordPress: {result.get('metadata', {}).get('error', 'Unknown error')}", + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + + @action(detail=True, methods=['post'], url_path='unpublish', url_name='unpublish', permission_classes=[IsAuthenticatedAndActive, IsEditorOrAbove]) + def unpublish(self, request, pk=None): + """ + STAGE 3: Unpublish content - clear external references and revert to draft. + Note: This does NOT delete the WordPress post, only clears the link. + + POST /api/v1/writer/content/{id}/unpublish/ + """ + content = self.get_object() + + if not content.external_id: + return error_response( + error='Content is not published', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + # Store the old values for response + old_external_id = content.external_id + old_external_url = content.external_url + + # Clear external references and revert status + content.external_id = None + content.external_url = None + content.status = 'draft' + content.save(update_fields=['external_id', 'external_url', 'status', 'updated_at']) + + return success_response( + data={ + 'content_id': content.id, + 'status': content.status, + 'was_external_id': old_external_id, + 'was_external_url': old_external_url, + }, + message='Content unpublished successfully. WordPress post was not deleted.', + request=request + ) + + @action(detail=False, methods=['post'], url_path='generate_image_prompts', url_name='generate_image_prompts') + def generate_image_prompts(self, request): + """Generate image prompts for content records - same pattern as other AI functions""" + from igny8_core.ai.tasks import run_ai_task + + account = getattr(request, 'account', None) + ids = request.data.get('ids', []) + + if not ids: + return error_response( + error='No IDs provided', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + account_id = account.id if account else None + + # Queue Celery task + try: + if hasattr(run_ai_task, 'delay'): + task = run_ai_task.delay( + function_name='generate_image_prompts', + payload={'ids': ids}, + account_id=account_id + ) + return success_response( + data={'task_id': str(task.id)}, + message='Image prompt generation started', + request=request + ) + else: + # Fallback to synchronous execution + result = run_ai_task( + function_name='generate_image_prompts', + payload={'ids': ids}, + account_id=account_id + ) + if result.get('success'): + return success_response( + data={'prompts_created': result.get('count', 0)}, + message='Image prompts generated successfully', + request=request + ) + else: + return error_response( + error=result.get('error', 'Image prompt generation failed'), + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + except Exception as e: + return error_response( + error=str(e), + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + + @action(detail=True, methods=['get'], url_path='validation', url_name='validation') + def validation(self, request, pk=None): + """ + Stage 3: Get validation checklist for content. + + GET /api/v1/writer/content/{id}/validation/ + Returns aggregated validation checklist for Writer UI. + """ + content = self.get_object() + validation_service = ContentValidationService() + + errors = validation_service.validate_content(content) + publish_errors = validation_service.validate_for_publish(content) + + return success_response( + data={ + 'content_id': content.id, + 'is_valid': len(errors) == 0, + 'ready_to_publish': len(publish_errors) == 0, + 'validation_errors': errors, + 'publish_errors': publish_errors, + 'metadata': { + 'has_entity_type': bool(content.entity_type), + 'entity_type': content.entity_type, + 'has_cluster_mapping': self._has_cluster_mapping(content), + 'has_taxonomy_mapping': self._has_taxonomy_mapping(content), + } + }, + request=request + ) + + @action(detail=True, methods=['post'], url_path='validate', url_name='validate') + def validate(self, request, pk=None): + """ + Stage 3: Re-run validators and return actionable errors. + + POST /api/v1/writer/content/{id}/validate/ + Re-validates content and returns structured errors. + """ + content = self.get_object() + validation_service = ContentValidationService() + + # Persist metadata mappings if task exists + if content.task: + mapping_service = MetadataMappingService() + mapping_service.persist_task_metadata_to_content(content) + + errors = validation_service.validate_for_publish(content) + + return success_response( + data={ + 'content_id': content.id, + 'is_valid': len(errors) == 0, + 'errors': errors, + }, + request=request + ) + + def _has_cluster_mapping(self, content): + """Helper to check if content has cluster mapping""" + from igny8_core.business.content.models import ContentClusterMap + return ContentClusterMap.objects.filter(content=content).exists() + + def _has_taxonomy_mapping(self, content): + """Helper to check if content has taxonomy mapping""" + from igny8_core.business.content.models import ContentTaxonomyMap + return ContentTaxonomyMap.objects.filter(content=content).exists() + + @action(detail=False, methods=['post'], url_path='generate_product', url_name='generate_product') + def generate_product(self, request): + """ + Generate product content (Phase 8). + + POST /api/v1/writer/content/generate_product/ + { + "name": "Product Name", + "description": "Product description", + "features": ["Feature 1", "Feature 2"], + "target_audience": "Target audience", + "primary_keyword": "Primary keyword", + "site_id": 1, // optional + "sector_id": 1 // optional + } + """ + from igny8_core.business.content.services.content_generation_service import ContentGenerationService + from igny8_core.auth.models import Site, Sector + + account = getattr(request, 'account', None) + if not account: + return error_response( + error='Account not found', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + product_data = request.data + site_id = product_data.get('site_id') + sector_id = product_data.get('sector_id') + + site = None + sector = None + + if site_id: + try: + site = Site.objects.get(id=site_id, account=account) + except Site.DoesNotExist: + return error_response( + error='Site not found', + status_code=status.HTTP_404_NOT_FOUND, + request=request + ) + + if sector_id: + try: + sector = Sector.objects.get(id=sector_id, account=account) + except Sector.DoesNotExist: + return error_response( + error='Sector not found', + status_code=status.HTTP_404_NOT_FOUND, + request=request + ) + + service = ContentGenerationService() + + try: + result = service.generate_product_content( + product_data=product_data, + account=account, + site=site, + sector=sector + ) + + if result.get('success'): + return success_response( + data={'task_id': result.get('task_id')}, + message=result.get('message', 'Product content generation started'), + request=request + ) + else: + return error_response( + error=result.get('error', 'Product content generation failed'), + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + except Exception as e: + return error_response( + error=str(e), + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + + @action(detail=True, methods=['get'], url_path='validation', url_name='validation') + def validation(self, request, pk=None): + """ + Stage 3: Get validation checklist for content. + + GET /api/v1/writer/content/{id}/validation/ + Returns aggregated validation checklist for Writer UI. + """ + content = self.get_object() + validation_service = ContentValidationService() + + errors = validation_service.validate_content(content) + publish_errors = validation_service.validate_for_publish(content) + + return success_response( + data={ + 'content_id': content.id, + 'is_valid': len(errors) == 0, + 'ready_to_publish': len(publish_errors) == 0, + 'validation_errors': errors, + 'publish_errors': publish_errors, + 'metadata': { + 'has_entity_type': bool(content.entity_type), + 'entity_type': content.entity_type, + 'has_cluster_mapping': self._has_cluster_mapping(content), + 'has_taxonomy_mapping': self._has_taxonomy_mapping(content), + } + }, + request=request + ) + + @action(detail=True, methods=['post'], url_path='validate', url_name='validate') + def validate(self, request, pk=None): + """ + Stage 3: Re-run validators and return actionable errors. + + POST /api/v1/writer/content/{id}/validate/ + Re-validates content and returns structured errors. + """ + content = self.get_object() + validation_service = ContentValidationService() + + # Persist metadata mappings if task exists + if content.task: + mapping_service = MetadataMappingService() + mapping_service.persist_task_metadata_to_content(content) + + errors = validation_service.validate_for_publish(content) + + return success_response( + data={ + 'content_id': content.id, + 'is_valid': len(errors) == 0, + 'errors': errors, + }, + request=request + ) + + def _has_cluster_mapping(self, content): + """Helper to check if content has cluster mapping""" + from igny8_core.business.content.models import ContentClusterMap + return ContentClusterMap.objects.filter(content=content).exists() + + def _has_taxonomy_mapping(self, content): + """Helper to check if content has taxonomy mapping""" + from igny8_core.business.content.models import ContentTaxonomyMap + return ContentTaxonomyMap.objects.filter(content=content).exists() + + @action(detail=False, methods=['post'], url_path='generate_service', url_name='generate_service') + def generate_service(self, request): + """ + Generate service page content (Phase 8). + + POST /api/v1/writer/content/generate_service/ + { + "name": "Service Name", + "description": "Service description", + "benefits": ["Benefit 1", "Benefit 2"], + "target_audience": "Target audience", + "primary_keyword": "Primary keyword", + "site_id": 1, // optional + "sector_id": 1 // optional + } + """ + from igny8_core.business.content.services.content_generation_service import ContentGenerationService + from igny8_core.auth.models import Site, Sector + + account = getattr(request, 'account', None) + if not account: + return error_response( + error='Account not found', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + service_data = request.data + site_id = service_data.get('site_id') + sector_id = service_data.get('sector_id') + + site = None + sector = None + + if site_id: + try: + site = Site.objects.get(id=site_id, account=account) + except Site.DoesNotExist: + return error_response( + error='Site not found', + status_code=status.HTTP_404_NOT_FOUND, + request=request + ) + + if sector_id: + try: + sector = Sector.objects.get(id=sector_id, account=account) + except Sector.DoesNotExist: + return error_response( + error='Sector not found', + status_code=status.HTTP_404_NOT_FOUND, + request=request + ) + + service = ContentGenerationService() + + try: + result = service.generate_service_page( + service_data=service_data, + account=account, + site=site, + sector=sector + ) + + if result.get('success'): + return success_response( + data={'task_id': result.get('task_id')}, + message=result.get('message', 'Service page generation started'), + request=request + ) + else: + return error_response( + error=result.get('error', 'Service page generation failed'), + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + except Exception as e: + return error_response( + error=str(e), + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + + @action(detail=True, methods=['get'], url_path='validation', url_name='validation') + def validation(self, request, pk=None): + """ + Stage 3: Get validation checklist for content. + + GET /api/v1/writer/content/{id}/validation/ + Returns aggregated validation checklist for Writer UI. + """ + content = self.get_object() + validation_service = ContentValidationService() + + errors = validation_service.validate_content(content) + publish_errors = validation_service.validate_for_publish(content) + + return success_response( + data={ + 'content_id': content.id, + 'is_valid': len(errors) == 0, + 'ready_to_publish': len(publish_errors) == 0, + 'validation_errors': errors, + 'publish_errors': publish_errors, + 'metadata': { + 'has_entity_type': bool(content.entity_type), + 'entity_type': content.entity_type, + 'has_cluster_mapping': self._has_cluster_mapping(content), + 'has_taxonomy_mapping': self._has_taxonomy_mapping(content), + } + }, + request=request + ) + + @action(detail=True, methods=['post'], url_path='validate', url_name='validate') + def validate(self, request, pk=None): + """ + Stage 3: Re-run validators and return actionable errors. + + POST /api/v1/writer/content/{id}/validate/ + Re-validates content and returns structured errors. + """ + content = self.get_object() + validation_service = ContentValidationService() + + # Persist metadata mappings if task exists + if content.task: + mapping_service = MetadataMappingService() + mapping_service.persist_task_metadata_to_content(content) + + errors = validation_service.validate_for_publish(content) + + return success_response( + data={ + 'content_id': content.id, + 'is_valid': len(errors) == 0, + 'errors': errors, + }, + request=request + ) + + def _has_cluster_mapping(self, content): + """Helper to check if content has cluster mapping""" + from igny8_core.business.content.models import ContentClusterMap + return ContentClusterMap.objects.filter(content=content).exists() + + def _has_taxonomy_mapping(self, content): + """Helper to check if content has taxonomy mapping""" + from igny8_core.business.content.models import ContentTaxonomyMap + return ContentTaxonomyMap.objects.filter(content=content).exists() + + @action(detail=False, methods=['post'], url_path='generate_taxonomy', url_name='generate_taxonomy') + def generate_taxonomy(self, request): + """ + Generate taxonomy page content (Phase 8). + + POST /api/v1/writer/content/generate_taxonomy/ + { + "name": "Taxonomy Name", + "description": "Taxonomy description", + "items": ["Item 1", "Item 2"], + "primary_keyword": "Primary keyword", + "site_id": 1, // optional + "sector_id": 1 // optional + } + """ + from igny8_core.business.content.services.content_generation_service import ContentGenerationService + from igny8_core.auth.models import Site, Sector + + account = getattr(request, 'account', None) + if not account: + return error_response( + error='Account not found', + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + taxonomy_data = request.data + site_id = taxonomy_data.get('site_id') + sector_id = taxonomy_data.get('sector_id') + + site = None + sector = None + + if site_id: + try: + site = Site.objects.get(id=site_id, account=account) + except Site.DoesNotExist: + return error_response( + error='Site not found', + status_code=status.HTTP_404_NOT_FOUND, + request=request + ) + + if sector_id: + try: + sector = Sector.objects.get(id=sector_id, account=account) + except Sector.DoesNotExist: + return error_response( + error='Sector not found', + status_code=status.HTTP_404_NOT_FOUND, + request=request + ) + + service = ContentGenerationService() + + try: + result = service.generate_taxonomy( + taxonomy_data=taxonomy_data, + account=account, + site=site, + sector=sector + ) + + if result.get('success'): + return success_response( + data={'task_id': result.get('task_id')}, + message=result.get('message', 'Taxonomy generation started'), + request=request + ) + else: + return error_response( + error=result.get('error', 'Taxonomy generation failed'), + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + except Exception as e: + return error_response( + error=str(e), + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + + @action(detail=True, methods=['get'], url_path='validation', url_name='validation') + def validation(self, request, pk=None): + """ + Stage 3: Get validation checklist for content. + + GET /api/v1/writer/content/{id}/validation/ + Returns aggregated validation checklist for Writer UI. + """ + content = self.get_object() + validation_service = ContentValidationService() + + errors = validation_service.validate_content(content) + publish_errors = validation_service.validate_for_publish(content) + + return success_response( + data={ + 'content_id': content.id, + 'is_valid': len(errors) == 0, + 'ready_to_publish': len(publish_errors) == 0, + 'validation_errors': errors, + 'publish_errors': publish_errors, + 'metadata': { + 'has_entity_type': bool(content.entity_type), + 'entity_type': content.entity_type, + 'has_cluster_mapping': self._has_cluster_mapping(content), + 'has_taxonomy_mapping': self._has_taxonomy_mapping(content), + } + }, + request=request + ) + + @action(detail=True, methods=['post'], url_path='validate', url_name='validate') + def validate(self, request, pk=None): + """ + Stage 3: Re-run validators and return actionable errors. + + POST /api/v1/writer/content/{id}/validate/ + Re-validates content and returns structured errors. + """ + content = self.get_object() + validation_service = ContentValidationService() + + # Persist metadata mappings if task exists + if content.task: + mapping_service = MetadataMappingService() + mapping_service.persist_task_metadata_to_content(content) + + errors = validation_service.validate_for_publish(content) + + return success_response( + data={ + 'content_id': content.id, + 'is_valid': len(errors) == 0, + 'errors': errors, + }, + request=request + ) + + def _has_cluster_mapping(self, content): + """Helper to check if content has cluster mapping""" + from igny8_core.business.content.models import ContentClusterMap + return ContentClusterMap.objects.filter(content=content).exists() + + def _has_taxonomy_mapping(self, content): + """Helper to check if content has taxonomy mapping""" + # Check new M2M relationship + return content.taxonomies.exists() + + +@extend_schema_view( + list=extend_schema(tags=['Writer - Taxonomies']), + create=extend_schema(tags=['Writer - Taxonomies']), + retrieve=extend_schema(tags=['Writer - Taxonomies']), + update=extend_schema(tags=['Writer - Taxonomies']), + partial_update=extend_schema(tags=['Writer - Taxonomies']), + destroy=extend_schema(tags=['Writer - Taxonomies']), +) +class ContentTaxonomyViewSet(SiteSectorModelViewSet): + """ + ViewSet for managing content taxonomies (categories, tags, product attributes) + Unified API Standard v1.0 compliant + """ + queryset = ContentTaxonomy.objects.select_related('parent', 'site', 'sector').prefetch_related('clusters', 'contents') + serializer_class = ContentTaxonomySerializer + permission_classes = [IsAuthenticatedAndActive, IsViewerOrAbove] + pagination_class = CustomPageNumberPagination + throttle_scope = 'writer' + throttle_classes = [DebugScopedRateThrottle] + + # DRF filtering configuration + filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] + + # Search configuration + search_fields = ['name', 'slug', 'description', 'external_taxonomy'] + + # Ordering configuration + ordering_fields = ['name', 'taxonomy_type', 'count', 'created_at'] + ordering = ['taxonomy_type', 'name'] + + # Filter configuration + filterset_fields = ['taxonomy_type', 'sync_status', 'parent', 'external_id', 'external_taxonomy'] + + def perform_create(self, serializer): + """Create taxonomy with site/sector context""" + user = getattr(self.request, 'user', None) + + try: + query_params = getattr(self.request, 'query_params', None) + if query_params is None: + query_params = getattr(self.request, 'GET', {}) + except AttributeError: + query_params = {} + + site_id = serializer.validated_data.get('site_id') or query_params.get('site_id') + sector_id = serializer.validated_data.get('sector_id') or query_params.get('sector_id') + + from igny8_core.auth.models import Site, Sector + from rest_framework.exceptions import ValidationError + + if not site_id: + raise ValidationError("site_id is required") + + try: + site = Site.objects.get(id=site_id) + except Site.DoesNotExist: + raise ValidationError(f"Site with id {site_id} does not exist") + + if not sector_id: + raise ValidationError("sector_id is required") + + try: + sector = Sector.objects.get(id=sector_id) + if sector.site_id != site_id: + raise ValidationError(f"Sector does not belong to the selected site") + except Sector.DoesNotExist: + raise ValidationError(f"Sector with id {sector_id} does not exist") + + serializer.validated_data.pop('site_id', None) + serializer.validated_data.pop('sector_id', None) + + account = getattr(self.request, 'account', None) + if not account and user and user.is_authenticated and user.account: + account = user.account + if not account: + account = site.account + + serializer.save(account=account, site=site, sector=sector) + + @action(detail=True, methods=['post'], permission_classes=[IsAuthenticatedAndActive, IsEditorOrAbove]) + def map_to_cluster(self, request, pk=None): + """Map taxonomy to semantic cluster""" + taxonomy = self.get_object() + cluster_id = request.data.get('cluster_id') + + if not cluster_id: + return error_response( + error="cluster_id is required", + status_code=status.HTTP_400_BAD_REQUEST, + request=request + ) + + from igny8_core.business.planning.models import Clusters + try: + cluster = Clusters.objects.get(id=cluster_id, site=taxonomy.site) + taxonomy.clusters.add(cluster) + + return success_response( + data={'message': f'Taxonomy "{taxonomy.name}" mapped to cluster "{cluster.name}"'}, + message="Taxonomy mapped to cluster successfully", + request=request + ) + except Clusters.DoesNotExist: + return error_response( + error=f"Cluster with id {cluster_id} not found", + status_code=status.HTTP_404_NOT_FOUND, + request=request + ) + + @action(detail=True, methods=['get']) + def contents(self, request, pk=None): + """Get all content associated with this taxonomy""" + taxonomy = self.get_object() + contents = taxonomy.contents.all() + + serializer = ContentSerializer(contents, many=True, context={'request': request}) + + return success_response( + data=serializer.data, + message=f"Found {contents.count()} content items for taxonomy '{taxonomy.name}'", + request=request + ) + + +# ContentAttributeViewSet temporarily disabled - ContentAttributeSerializer was removed in Stage 1 +# TODO: Re-implement or remove completely based on Stage 1 architecture decisions + + diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index ea77c9c6..9bfb2f9a 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -80,6 +80,7 @@ const Plans = lazy(() => import("./pages/Settings/Plans")); const Industries = lazy(() => import("./pages/Settings/Industries")); const Status = lazy(() => import("./pages/Settings/Status")); const ApiMonitor = lazy(() => import("./pages/Settings/ApiMonitor")); +const DebugStatus = lazy(() => import("./pages/Settings/DebugStatus")); const Integration = lazy(() => import("./pages/Settings/Integration")); const Publishing = lazy(() => import("./pages/Settings/Publishing")); const Sites = lazy(() => import("./pages/Settings/Sites")); @@ -428,6 +429,11 @@ export default function App() { } /> + + + + } /> diff --git a/frontend/src/layout/AppSidebar.tsx b/frontend/src/layout/AppSidebar.tsx index 31621723..d2ce57e8 100644 --- a/frontend/src/layout/AppSidebar.tsx +++ b/frontend/src/layout/AppSidebar.tsx @@ -238,6 +238,7 @@ const AppSidebar: React.FC = () => { subItems: [ { name: "Status", path: "/settings/status" }, { name: "API Monitor", path: "/settings/api-monitor" }, + { name: "Debug Status", path: "/settings/debug-status" }, ], }, { diff --git a/frontend/src/pages/Settings/DebugStatus.tsx b/frontend/src/pages/Settings/DebugStatus.tsx new file mode 100644 index 00000000..08df6d54 --- /dev/null +++ b/frontend/src/pages/Settings/DebugStatus.tsx @@ -0,0 +1,802 @@ +import { useState, useEffect, useCallback } from "react"; +import PageMeta from "../../components/common/PageMeta"; +import ComponentCard from "../../components/common/ComponentCard"; +import { API_BASE_URL, fetchAPI } from "../../services/api"; + +interface HealthCheck { + name: string; + description: string; + status: 'healthy' | 'warning' | 'error' | 'checking'; + message?: string; + details?: string; + lastChecked?: string; +} + +interface ModuleHealth { + module: string; + description: string; + checks: HealthCheck[]; +} + +const getStatusColor = (status: string) => { + switch (status) { + case 'healthy': return 'text-green-600 dark:text-green-400'; + case 'warning': return 'text-yellow-600 dark:text-yellow-400'; + case 'error': return 'text-red-600 dark:text-red-400'; + case 'checking': return 'text-blue-600 dark:text-blue-400'; + default: return 'text-gray-600 dark:text-gray-400'; + } +}; + +const getStatusBadge = (status: string) => { + switch (status) { + case 'healthy': return 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400'; + case 'warning': return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400'; + case 'error': return 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400'; + case 'checking': return 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400'; + default: return 'bg-gray-100 text-gray-800 dark:bg-gray-900/30 dark:text-gray-400'; + } +}; + +const getStatusIcon = (status: string) => { + switch (status) { + case 'healthy': return '✓'; + case 'warning': return '⚠'; + case 'error': return '✗'; + case 'checking': return '⟳'; + default: return '?'; + } +}; + +export default function DebugStatus() { + const [moduleHealths, setModuleHealths] = useState([]); + const [loading, setLoading] = useState(false); + + // Helper to get auth token + const getAuthToken = () => { + const token = localStorage.getItem('auth_token') || + (() => { + try { + const authStorage = localStorage.getItem('auth-storage'); + if (authStorage) { + const parsed = JSON.parse(authStorage); + return parsed?.state?.token || ''; + } + } catch (e) { + // Ignore parsing errors + } + return ''; + })(); + return token; + }; + + // Helper to make authenticated API calls + const apiCall = async (path: string, method: string = 'GET', body?: any) => { + const token = getAuthToken(); + const headers: HeadersInit = { + 'Content-Type': 'application/json', + }; + + if (token) { + headers['Authorization'] = `Bearer ${token}`; + } + + const options: RequestInit = { + method, + headers, + credentials: 'include', + }; + + if (body && method !== 'GET') { + options.body = JSON.stringify(body); + } + + const response = await fetch(`${API_BASE_URL}${path}`, options); + const data = await response.json(); + return { response, data }; + }; + + // Check database schema field mappings (the issues we just fixed) + const checkDatabaseSchemaMapping = useCallback(async (): Promise => { + try { + // Test Writer Content endpoint (was failing with entity_type error) + const { response: contentResp, data: contentData } = await apiCall('/v1/writer/content/'); + + if (!contentResp.ok) { + return { + name: 'Database Schema Mapping', + description: 'Checks if model field names map correctly to database columns', + status: 'error', + message: `Writer Content API failed with ${contentResp.status}`, + details: 'Model fields may not be mapped to database columns correctly (e.g., content_type vs entity_type)', + lastChecked: new Date().toISOString(), + }; + } + + // Check if response has the expected structure with new field names + if (contentData?.results && Array.isArray(contentData.results)) { + // If we can fetch content, schema mapping is working + return { + name: 'Database Schema Mapping', + description: 'Checks if model field names map correctly to database columns', + status: 'healthy', + message: 'All model fields correctly mapped via db_column attributes', + details: `Content API working correctly. Fields like content_type, content_html, content_structure are properly mapped.`, + lastChecked: new Date().toISOString(), + }; + } + + return { + name: 'Database Schema Mapping', + description: 'Checks if model field names map correctly to database columns', + status: 'warning', + message: 'Content API returned unexpected structure', + details: 'Response format may have changed', + lastChecked: new Date().toISOString(), + }; + } catch (error: any) { + return { + name: 'Database Schema Mapping', + description: 'Checks if model field names map correctly to database columns', + status: 'error', + message: error.message || 'Failed to check schema mapping', + details: 'Check if db_column attributes are set correctly in models', + lastChecked: new Date().toISOString(), + }; + } + }, []); + + // Check Writer module health + const checkWriterModule = useCallback(async (): Promise => { + const checks: HealthCheck[] = []; + + // Check Content endpoint + try { + const { response: contentResp, data: contentData } = await apiCall('/v1/writer/content/'); + + if (contentResp.ok && contentData?.success !== false) { + checks.push({ + name: 'Content List', + description: 'Writer content listing endpoint', + status: 'healthy', + message: `Found ${contentData?.count || 0} content items`, + lastChecked: new Date().toISOString(), + }); + } else { + checks.push({ + name: 'Content List', + description: 'Writer content listing endpoint', + status: 'error', + message: contentData?.error || `Failed with ${contentResp.status}`, + details: 'Check model field mappings (content_type, content_html, content_structure)', + lastChecked: new Date().toISOString(), + }); + } + } catch (error: any) { + checks.push({ + name: 'Content List', + description: 'Writer content listing endpoint', + status: 'error', + message: error.message || 'Network error', + lastChecked: new Date().toISOString(), + }); + } + + // Check Tasks endpoint + try { + const { response: tasksResp, data: tasksData } = await apiCall('/v1/writer/tasks/'); + + if (tasksResp.ok && tasksData?.success !== false) { + checks.push({ + name: 'Tasks List', + description: 'Writer tasks listing endpoint', + status: 'healthy', + message: `Found ${tasksData?.count || 0} tasks`, + lastChecked: new Date().toISOString(), + }); + } else { + checks.push({ + name: 'Tasks List', + description: 'Writer tasks listing endpoint', + status: 'error', + message: tasksData?.error || `Failed with ${tasksResp.status}`, + details: 'Check model field mappings (content_type, content_structure, taxonomy_term)', + lastChecked: new Date().toISOString(), + }); + } + } catch (error: any) { + checks.push({ + name: 'Tasks List', + description: 'Writer tasks listing endpoint', + status: 'error', + message: error.message || 'Network error', + lastChecked: new Date().toISOString(), + }); + } + + // Check Content Validation + try { + // Get first content ID if available + const { data: contentData } = await apiCall('/v1/writer/content/'); + const firstContentId = contentData?.results?.[0]?.id; + + if (firstContentId) { + const { response: validationResp, data: validationData } = await apiCall( + `/v1/writer/content/${firstContentId}/validation/` + ); + + if (validationResp.ok && validationData?.success !== false) { + checks.push({ + name: 'Content Validation', + description: 'Content validation before publish', + status: 'healthy', + message: 'Validation endpoint working', + lastChecked: new Date().toISOString(), + }); + } else { + checks.push({ + name: 'Content Validation', + description: 'Content validation before publish', + status: 'error', + message: validationData?.error || `Failed with ${validationResp.status}`, + details: 'Check validation_service.py field references (content_html, content_type)', + lastChecked: new Date().toISOString(), + }); + } + } else { + checks.push({ + name: 'Content Validation', + description: 'Content validation before publish', + status: 'warning', + message: 'No content available to test validation', + lastChecked: new Date().toISOString(), + }); + } + } catch (error: any) { + checks.push({ + name: 'Content Validation', + description: 'Content validation before publish', + status: 'error', + message: error.message || 'Network error', + lastChecked: new Date().toISOString(), + }); + } + + return checks; + }, []); + + // Check Planner module health + const checkPlannerModule = useCallback(async (): Promise => { + const checks: HealthCheck[] = []; + + // Check Clusters endpoint + try { + const { response: clustersResp, data: clustersData } = await apiCall('/v1/planner/clusters/'); + + if (clustersResp.ok && clustersData?.success !== false) { + checks.push({ + name: 'Clusters List', + description: 'Planner clusters listing endpoint', + status: 'healthy', + message: `Found ${clustersData?.count || 0} clusters`, + lastChecked: new Date().toISOString(), + }); + } else { + checks.push({ + name: 'Clusters List', + description: 'Planner clusters listing endpoint', + status: 'error', + message: clustersData?.error || `Failed with ${clustersResp.status}`, + lastChecked: new Date().toISOString(), + }); + } + } catch (error: any) { + checks.push({ + name: 'Clusters List', + description: 'Planner clusters listing endpoint', + status: 'error', + message: error.message || 'Network error', + lastChecked: new Date().toISOString(), + }); + } + + // Check Keywords endpoint + try { + const { response: keywordsResp, data: keywordsData } = await apiCall('/v1/planner/keywords/'); + + if (keywordsResp.ok && keywordsData?.success !== false) { + checks.push({ + name: 'Keywords List', + description: 'Planner keywords listing endpoint', + status: 'healthy', + message: `Found ${keywordsData?.count || 0} keywords`, + lastChecked: new Date().toISOString(), + }); + } else { + checks.push({ + name: 'Keywords List', + description: 'Planner keywords listing endpoint', + status: 'error', + message: keywordsData?.error || `Failed with ${keywordsResp.status}`, + lastChecked: new Date().toISOString(), + }); + } + } catch (error: any) { + checks.push({ + name: 'Keywords List', + description: 'Planner keywords listing endpoint', + status: 'error', + message: error.message || 'Network error', + lastChecked: new Date().toISOString(), + }); + } + + // Check Ideas endpoint + try { + const { response: ideasResp, data: ideasData } = await apiCall('/v1/planner/ideas/'); + + if (ideasResp.ok && ideasData?.success !== false) { + checks.push({ + name: 'Ideas List', + description: 'Planner ideas listing endpoint', + status: 'healthy', + message: `Found ${ideasData?.count || 0} ideas`, + lastChecked: new Date().toISOString(), + }); + } else { + checks.push({ + name: 'Ideas List', + description: 'Planner ideas listing endpoint', + status: 'error', + message: ideasData?.error || `Failed with ${ideasResp.status}`, + lastChecked: new Date().toISOString(), + }); + } + } catch (error: any) { + checks.push({ + name: 'Ideas List', + description: 'Planner ideas listing endpoint', + status: 'error', + message: error.message || 'Network error', + lastChecked: new Date().toISOString(), + }); + } + + return checks; + }, []); + + // Check Sites module health + const checkSitesModule = useCallback(async (): Promise => { + const checks: HealthCheck[] = []; + + // Check Sites list + try { + const { response: sitesResp, data: sitesData } = await apiCall('/v1/auth/sites/'); + + if (sitesResp.ok && sitesData?.success !== false) { + checks.push({ + name: 'Sites List', + description: 'Sites listing endpoint', + status: 'healthy', + message: `Found ${sitesData?.count || sitesData?.results?.length || 0} sites`, + lastChecked: new Date().toISOString(), + }); + } else { + checks.push({ + name: 'Sites List', + description: 'Sites listing endpoint', + status: 'error', + message: sitesData?.error || `Failed with ${sitesResp.status}`, + lastChecked: new Date().toISOString(), + }); + } + } catch (error: any) { + checks.push({ + name: 'Sites List', + description: 'Sites listing endpoint', + status: 'error', + message: error.message || 'Network error', + lastChecked: new Date().toISOString(), + }); + } + + return checks; + }, []); + + // Check Integration module health + const checkIntegrationModule = useCallback(async (): Promise => { + const checks: HealthCheck[] = []; + + // Check Integration content types endpoint + try { + // Get first site ID if available + const { data: sitesData } = await apiCall('/v1/auth/sites/'); + const firstSiteId = sitesData?.results?.[0]?.id || sitesData?.[0]?.id; + + if (firstSiteId) { + const { response: contentTypesResp, data: contentTypesData } = await apiCall( + `/v1/integration/integrations/${firstSiteId}/content-types/` + ); + + if (contentTypesResp.ok && contentTypesData?.success !== false) { + checks.push({ + name: 'Content Types Sync', + description: 'Integration content types endpoint', + status: 'healthy', + message: 'Content types endpoint working', + lastChecked: new Date().toISOString(), + }); + } else { + checks.push({ + name: 'Content Types Sync', + description: 'Integration content types endpoint', + status: 'error', + message: contentTypesData?.error || `Failed with ${contentTypesResp.status}`, + details: 'Check integration views field mappings (content_type_map vs entity_type_map)', + lastChecked: new Date().toISOString(), + }); + } + } else { + checks.push({ + name: 'Content Types Sync', + description: 'Integration content types endpoint', + status: 'warning', + message: 'No sites available to test integration', + lastChecked: new Date().toISOString(), + }); + } + } catch (error: any) { + checks.push({ + name: 'Content Types Sync', + description: 'Integration content types endpoint', + status: 'error', + message: error.message || 'Network error', + lastChecked: new Date().toISOString(), + }); + } + + return checks; + }, []); + + // Check Content Manager module health (taxonomy relations) + const checkContentManagerModule = useCallback(async (): Promise => { + const checks: HealthCheck[] = []; + + // Check Taxonomy endpoint + try { + const { response: taxonomyResp, data: taxonomyData } = await apiCall('/v1/writer/taxonomy/'); + + if (taxonomyResp.ok && taxonomyData?.success !== false) { + checks.push({ + name: 'Taxonomy System', + description: 'Content taxonomy endpoint', + status: 'healthy', + message: `Found ${taxonomyData?.count || 0} taxonomy items`, + lastChecked: new Date().toISOString(), + }); + } else { + checks.push({ + name: 'Taxonomy System', + description: 'Content taxonomy endpoint', + status: 'error', + message: taxonomyData?.error || `Failed with ${taxonomyResp.status}`, + details: 'Check ContentTaxonomyRelation through model and field mappings', + lastChecked: new Date().toISOString(), + }); + } + } catch (error: any) { + checks.push({ + name: 'Taxonomy System', + description: 'Content taxonomy endpoint', + status: 'error', + message: error.message || 'Network error', + lastChecked: new Date().toISOString(), + }); + } + + return checks; + }, []); + + // Run all health checks + const runAllChecks = useCallback(async () => { + setLoading(true); + + try { + // Run schema check first + const schemaCheck = await checkDatabaseSchemaMapping(); + + // Run module checks in parallel + const [writerChecks, plannerChecks, sitesChecks, integrationChecks, contentMgrChecks] = await Promise.all([ + checkWriterModule(), + checkPlannerModule(), + checkSitesModule(), + checkIntegrationModule(), + checkContentManagerModule(), + ]); + + // Build module health results + const moduleHealthResults: ModuleHealth[] = [ + { + module: 'Database Schema', + description: 'Critical database field mapping checks', + checks: [schemaCheck], + }, + { + module: 'Writer Module', + description: 'Content creation and task management', + checks: writerChecks, + }, + { + module: 'Planner Module', + description: 'Keyword clustering and content planning', + checks: plannerChecks, + }, + { + module: 'Sites Module', + description: 'Site management and configuration', + checks: sitesChecks, + }, + { + module: 'Integration Module', + description: 'External platform sync (WordPress, etc.)', + checks: integrationChecks, + }, + { + module: 'Content Manager', + description: 'Taxonomy and content organization', + checks: contentMgrChecks, + }, + ]; + + setModuleHealths(moduleHealthResults); + } catch (error) { + console.error('Failed to run health checks:', error); + } finally { + setLoading(false); + } + }, [ + checkDatabaseSchemaMapping, + checkWriterModule, + checkPlannerModule, + checkSitesModule, + checkIntegrationModule, + checkContentManagerModule, + ]); + + // Run checks on mount + useEffect(() => { + runAllChecks(); + }, [runAllChecks]); + + // Calculate module status + const getModuleStatus = (module: ModuleHealth): 'error' | 'warning' | 'healthy' => { + const statuses = module.checks.map(c => c.status); + if (statuses.some(s => s === 'error')) return 'error'; + if (statuses.some(s => s === 'warning')) return 'warning'; + return 'healthy'; + }; + + // Calculate overall health + const getOverallHealth = () => { + const allStatuses = moduleHealths.flatMap(m => m.checks.map(c => c.status)); + const total = allStatuses.length; + const healthy = allStatuses.filter(s => s === 'healthy').length; + const warning = allStatuses.filter(s => s === 'warning').length; + const error = allStatuses.filter(s => s === 'error').length; + + let status: 'error' | 'warning' | 'healthy' = 'healthy'; + if (error > 0) status = 'error'; + else if (warning > 0) status = 'warning'; + + return { total, healthy, warning, error, status, percentage: total > 0 ? Math.round((healthy / total) * 100) : 0 }; + }; + + const overallHealth = getOverallHealth(); + + return ( + <> + + +
+ {/* Header */} +
+
+

Debug Status

+

+ Comprehensive health checks for all modules and recent bug fixes +

+
+ +
+ + {/* Overall Health Summary */} + + Overall System Health + + {getStatusIcon(overallHealth.status)} + +
+ } + desc={ + overallHealth.status === 'error' + ? `${overallHealth.error} critical issue${overallHealth.error !== 1 ? 's' : ''} detected` + : overallHealth.status === 'warning' + ? `${overallHealth.warning} warning${overallHealth.warning !== 1 ? 's' : ''} detected` + : 'All systems operational' + } + > +
+ {/* Health Percentage */} +
+
+ {overallHealth.percentage}% +
+
+ {overallHealth.healthy} of {overallHealth.total} checks passed +
+
+ + {/* Health Breakdown */} +
+
+
+ {overallHealth.healthy} +
+
Healthy
+
+
+
+ {overallHealth.warning} +
+
Warnings
+
+
+
+ {overallHealth.error} +
+
Errors
+
+
+
+ + + {/* Module Health Cards */} +
+ {moduleHealths.map((moduleHealth, index) => { + const moduleStatus = getModuleStatus(moduleHealth); + const healthyCount = moduleHealth.checks.filter(c => c.status === 'healthy').length; + const totalCount = moduleHealth.checks.length; + + return ( + + {moduleHealth.module} + + {getStatusIcon(moduleStatus)} + +
+ } + desc={ + moduleStatus === 'error' + ? `Issues detected - ${healthyCount}/${totalCount} checks passed` + : moduleStatus === 'warning' + ? `Warnings detected - ${healthyCount}/${totalCount} checks passed` + : `All ${totalCount} checks passed` + } + > +
+

+ {moduleHealth.description} +

+ + {/* Health Checks List */} + {moduleHealth.checks.map((check, checkIndex) => ( +
+
+ + {getStatusIcon(check.status)} + +
+
+ + {check.name} + + + {check.status} + +
+

+ {check.description} +

+ {check.message && ( +

+ {check.message} +

+ )} + {check.details && ( +

+ 💡 {check.details} +

+ )} +
+
+
+ ))} +
+ + ); + })} + + + {/* Help Section */} + +
+
+

+ Database Schema Mapping Errors +

+

+ If you see errors about missing fields like entity_type, + cluster_role, or + html_content: +

+
    +
  • Check that model fields have correct db_column attributes
  • +
  • Verify database columns exist with SELECT column_name FROM information_schema.columns
  • +
  • Review DATABASE_SCHEMA_FIELD_MAPPING_GUIDE.md in repo root
  • +
+
+ +
+

+ Field Reference Errors in Code +

+

+ If API endpoints return 500 errors with AttributeError or similar: +

+
    +
  • Search codebase for old field names: entity_type, cluster_role, html_content
  • +
  • Replace with new names: content_type, content_structure, content_html
  • +
  • Check views, services, and serializers in writer/planner/integration modules
  • +
+
+ +
+

+ All Checks Passing? +

+

+ Great! Your system is healthy. This page will help you quickly diagnose issues if they appear in the future. + Bookmark this page and check it first when troubleshooting module-specific problems. +

+
+
+
+ + + ); +} diff --git a/frontend/src/pages/Writer/Tasks.tsx b/frontend/src/pages/Writer/Tasks.tsx index b4252d9a..39a12904 100644 --- a/frontend/src/pages/Writer/Tasks.tsx +++ b/frontend/src/pages/Writer/Tasks.tsx @@ -164,7 +164,7 @@ export default function Tasks() { setShowContent(true); setLoading(false); } - }, [currentPage, statusFilter, clusterFilter, structureFilter, typeFilter, entityTypeFilter, sortBy, sortDirection, searchTerm, activeSector, pageSize]); + }, [currentPage, statusFilter, clusterFilter, structureFilter, typeFilter, sortBy, sortDirection, searchTerm, activeSector, pageSize]); useEffect(() => { loadTasks(); @@ -513,7 +513,7 @@ export default function Tasks() { setTypeFilter, setCurrentPage, }); - }, [clusters, activeSector, formData, searchTerm, statusFilter, clusterFilter, structureFilter, typeFilter, sourceFilter, entityTypeFilter]); + }, [clusters, activeSector, formData, searchTerm, statusFilter, clusterFilter, structureFilter, typeFilter, sourceFilter]); // Calculate header metrics const headerMetrics = useMemo(() => {