# Feature Development Guide This guide documents the end-to-end workflow for building features in your composable monorepo. ## Quick Start ```bash # 1. Create feature branch git checkout -b feature/my-feature # 2. Implement API endpoint (use Wrap + Bind patterns) # 3. Implement frontend (use design system + auth) # 4. Write tests # 5. Run quality checks ./scripts/quality.sh # 6. Commit and push git add -A && git commit -m "feat: my feature" git push -u origin feature/my-feature ``` ## Architecture Overview ``` slack-q-1770281368/ ├── pkg/ # Shared Go packages (chassis) │ ├── app/ # Wrap, Bind, Health patterns │ ├── httperror/ # Typed HTTP errors │ ├── httpresponse/ # JSON response envelope │ └── auth/ # JWT + API key validation ├── packages/ # Shared TypeScript packages │ ├── ui/ # Design system components │ ├── layout/ # DashboardShell, Sidebar │ ├── auth/ # AuthProvider, useAuth │ └── api-client/ # Generated TypeScript client ├── services/ # Go backend services └── apps/ # Frontend applications ``` ## Backend Patterns ### Wrap Pattern Convert error-returning handlers to `http.HandlerFunc`: ```go import "slack-q-1770281368/pkg/app" func (h *Handler) GetItem() http.HandlerFunc { return app.Wrap(func(w http.ResponseWriter, r *http.Request) error { // Return errors - they become proper HTTP responses item, err := h.svc.Get(r.Context(), chi.URLParam(r, "id")) if err != nil { return httperror.NotFound("item not found") } httpresponse.JSON(w, http.StatusOK, item) return nil }) } ``` ### Bind Pattern Parse and validate request bodies in one call: ```go import "slack-q-1770281368/pkg/app" func (h *Handler) CreateItem() http.HandlerFunc { type request struct { Name string `json:"name" validate:"required,min=1,max=100"` Type string `json:"type" validate:"required,oneof=a b c"` } return app.Wrap(func(w http.ResponseWriter, r *http.Request) error { var req request if err := app.BindAndValidate(r, &req); err != nil { return err // Validation errors become 400 with details } // Use req.Name, req.Type... }) } ``` ### HTTPError Sentinels Use typed errors that map to HTTP status codes: ```go import "slack-q-1770281368/pkg/httperror" httperror.BadRequest("invalid input") // 400 httperror.Unauthorized("not authenticated") // 401 httperror.Forbidden("access denied") // 403 httperror.NotFound("resource not found") // 404 httperror.Conflict("already exists") // 409 httperror.Internal("something went wrong") // 500 // With formatted messages httperror.NotFoundf("user %s not found", userID) // With details httperror.WithDetails( httperror.BadRequest("validation failed"), map[string]string{"name": "required"}, ) ``` ### Auth Context Access the authenticated user from request context: ```go import "slack-q-1770281368/pkg/auth" user, ok := auth.GetUser(r.Context()) if !ok { return httperror.Unauthorized("not authenticated") } // user.ID, user.Email, user.Roles available ``` ## Frontend Patterns ### Design System Components Import from the shared UI package: ```tsx import { Button, Card, Input, Label, Badge } from '@slack-q-1770281368/ui'; import { DashboardShell, Sidebar, Header } from '@slack-q-1770281368/layout'; ``` ### Auth Hook Access auth state and actions: ```tsx import { useAuth } from '@slack-q-1770281368/auth'; function MyComponent() { const { user, isLoading, login, logout, refreshUser } = useAuth(); if (isLoading) return