Skip to content

Spaces Admin CRUD — Design Spec

For agentic workers: REQUIRED SUB-SKILL: Use compose:plan to create implementation plan from this spec.

Goal: Add complete CRUD management for Spaces, Space Groups, and Tags to the admin panel.

Architecture: Follow the existing 3-layer pattern (apiClient → hooks → components). Backend needs search/filter/ordering added to ViewSets. Frontend builds from scratch using the same patterns as Users CRUD.

Tech Stack: React 19, TanStack Router, TanStack Query, shadcn/ui (@repo/ui), Tailwind CSS


[S1] Problem

The admin panel has no way to manage Spaces, Space Groups, or Tags. These are core platform entities that admins need to create, edit, and delete. The backend has full CRUD endpoints but no search/filter/ordering configured for admin use.

[S2] Solution overview

Add three new admin CRUD screens following the established 3-layer pattern:

  1. Spaces — list with search/filter/sort, create/edit form dialog, delete confirmation, detail view
  2. Space Groups — list with search/sort, create/edit form dialog, delete confirmation
  3. Tags — list with search/sort, create/edit form dialog, delete confirmation

Backend changes: Add filter_backends, search_fields, ordering_fields, and filterset_fields to SpaceViewSet, SpaceGroupViewSet, and TagViewSet.

[S3] Backend changes

SpaceViewSet additions

python
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_fields = ['space_type', 'access_level', 'space_group', 'is_welcome_space']
search_fields = ['name', 'description']
ordering_fields = ['name', 'order', 'created_at']

SpaceGroupViewSet additions

python
filter_backends = [SearchFilter, OrderingFilter]
search_fields = ['name']
ordering_fields = ['name', 'order']

TagViewSet additions

python
filter_backends = [SearchFilter, OrderingFilter]
search_fields = ['name']
ordering_fields = ['name']

[S4] Frontend types

Shared types file types/space.ts:

  • Space — matches DRF serializer fields (id, space_group, name, slug, description, space_type, access_level, access_groups, is_welcome_space, order)
  • SpaceGroup — id, name, slug, order
  • Tag — id, name, slug

[S5] Space CRUD

List view

  • Paginated data table with columns: Name, Slug, Type, Access, Group, Order, Actions
  • Server-side search by name/description
  • Filter by space_type, access_level
  • Sort by name, order, created_at
  • Row actions: Edit, Delete
  • Header: "Novo Espaço" button opens create dialog

Create/Edit dialog (SpaceFormDialog)

  • Fields: name (required), slug (auto-generated, editable), description, space_type (select), access_level (select), space_group (select, loads from API), is_welcome_space (checkbox, only when space_type=basic), order (number)
  • On create: POST to /api/v1/spaces/
  • On edit: PATCH to /api/v1/spaces/{id}/
  • Toast feedback on success/error

Delete dialog

  • Confirmation with space name
  • DELETE to /api/v1/spaces/{id}/
  • Toast feedback

Detail view (/spaces/$spaceId)

  • Shows all space fields
  • Edit and Delete action buttons
  • Back link to list

[S6] Space Group CRUD

List view

  • Paginated data table: Name, Slug, Order, Actions
  • Search by name
  • Sort by name, order
  • Row actions: Edit, Delete

Create/Edit dialog (SpaceGroupFormDialog)

  • Fields: name (required), slug (auto-generated, editable), order (number)
  • POST/PATCH to /api/v1/space-groups/

Delete dialog

  • Confirmation with group name
  • DELETE to /api/v1/space-groups/{id}/

[S7] Tag CRUD

List view

  • Paginated data table: Name, Slug, Actions
  • Search by name
  • Sort by name
  • Row actions: Edit, Delete

Create/Edit dialog (TagFormDialog)

  • Fields: name (required), slug (auto-generated, editable)
  • POST/PATCH to /api/v1/tags/

Delete dialog

  • Confirmation with tag name
  • DELETE to /api/v1/tags/{id}/

[S8] Sidebar navigation

Update sidebar-data.ts:

  • Replace placeholder "Posts" item with "Espaços" → /spaces
  • Add "Groups" → /space-groups under Conteúdo
  • Add "Tags" → /tags under Conteúdo
  • Remove disabled: true from these items
  • Keep Events, Courses, Reports, Settings as disabled placeholders

[S9] Route registration

Add routes to TanStack Router file-based routing:

  • routes/spaces/index.tsx/spaces
  • routes/spaces/$spaceId.tsx/spaces/$spaceId
  • routes/space-groups.tsx/space-groups
  • routes/tags.tsx/tags

[S10] Banner/Icon

Banner and icon uploads are out of scope for this iteration. The DRF serializer does not expose these fields. Image management will be handled separately if needed.

[S11] Testing

  • TypeScript compilation passes (bunx tsc --noEmit)
  • All CRUD operations work against the real backend API
  • Toast feedback on all mutations
  • Skeleton loading states on all list/detail views

Strum — Documentação.