S

Senior Fullstack Expert

Comprehensive skill designed for comprehensive, fullstack, development, skill. Includes structured workflows, validation checks, and reusable patterns for development.

SkillClipticsdevelopmentv1.0.0MIT
0 views0 copies

Senior Fullstack Expert

A comprehensive skill for senior fullstack engineers covering frontend-backend integration, API design, database optimization, authentication flows, and end-to-end application architecture with modern web stacks.

When to Use This Skill

Choose this skill when:

  • Building end-to-end features spanning frontend, API, and database layers
  • Designing API contracts and data flows between client and server
  • Implementing authentication/authorization across the full stack
  • Optimizing database queries and frontend rendering together
  • Setting up full-stack development environments and tooling

Consider alternatives when:

  • Need deep frontend framework expertise → use a React/Vue/Angular skill
  • Working only on backend APIs → use a backend/API design skill
  • Need database design specifically → use a database design skill
  • Building mobile apps → use a React Native or mobile skill

Quick Start

// Full-stack feature: User Profile with optimistic updates // 1. API Route (Next.js App Router) // app/api/profile/route.ts import { NextRequest, NextResponse } from 'next/server'; import { auth } from '@/lib/auth'; import { db } from '@/lib/db'; import { z } from 'zod'; const updateSchema = z.object({ name: z.string().min(1).max(100), bio: z.string().max(500).optional(), avatarUrl: z.string().url().optional(), }); export async function PUT(req: NextRequest) { const session = await auth(); if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); const body = updateSchema.parse(await req.json()); const user = await db.user.update({ where: { id: session.user.id }, data: body, select: { id: true, name: true, bio: true, avatarUrl: true }, }); return NextResponse.json(user); }

Core Concepts

Full-Stack Architecture Layers

LayerTechnologyResponsibility
Client StateReact Query / SWRServer state cache, optimistic updates
UI ComponentsReact + TailwindRendering, user interaction
API LayerNext.js Routes / ExpressRequest handling, validation, auth
Business LogicService classesDomain rules, orchestration
Data AccessPrisma / DrizzleDatabase queries, migrations
DatabasePostgreSQL / MongoDBData persistence, indexing

Optimistic Update Pattern (Full Stack)

// Frontend: React Query mutation with optimistic update function useUpdateProfile() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (data: ProfileUpdate) => fetch('/api/profile', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }).then(r => { if (!r.ok) throw new Error('Update failed'); return r.json(); }), onMutate: async (newData) => { await queryClient.cancelQueries({ queryKey: ['profile'] }); const previous = queryClient.getQueryData(['profile']); queryClient.setQueryData(['profile'], (old: Profile) => ({ ...old, ...newData })); return { previous }; }, onError: (err, variables, context) => { queryClient.setQueryData(['profile'], context?.previous); toast.error('Failed to update profile'); }, onSettled: () => { queryClient.invalidateQueries({ queryKey: ['profile'] }); }, }); }

Authentication Flow (Full Stack)

// Middleware for route protection // middleware.ts import { NextResponse } from 'next/server'; import { getToken } from 'next-auth/jwt'; export async function middleware(req) { const token = await getToken({ req }); const isAuth = !!token; const isAuthPage = req.nextUrl.pathname.startsWith('/auth'); const isApiRoute = req.nextUrl.pathname.startsWith('/api'); const isPublicApi = req.nextUrl.pathname.startsWith('/api/public'); if (isAuthPage && isAuth) { return NextResponse.redirect(new URL('/dashboard', req.url)); } if (!isAuth && !isAuthPage && !isPublicApi) { if (isApiRoute) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } return NextResponse.redirect(new URL('/auth/login', req.url)); } return NextResponse.next(); } export const config = { matcher: ['/dashboard/:path*', '/api/:path*', '/auth/:path*'], };

Configuration

ParameterTypeDefaultDescription
frameworkstring'nextjs'Fullstack framework: nextjs, remix, or nuxt
ormstring'prisma'ORM: prisma, drizzle, or typeorm
authProviderstring'next-auth'Auth: next-auth, clerk, or lucia
stateManagementstring'react-query'Server state: react-query, swr, or trpc
cssFrameworkstring'tailwind'Styling: tailwind, css-modules, or styled
apiValidationstring'zod'Schema validation: zod, yup, or joi

Best Practices

  1. Validate data at every boundary: client, API, and database — Client validation provides instant feedback. API validation prevents malicious input. Database constraints catch bugs in business logic. Each layer serves a different purpose and all three are necessary.

  2. Use TypeScript end-to-end with shared types — Define API response types once and use them in both backend handlers and frontend consumers. Tools like tRPC or generated OpenAPI clients ensure type safety across the network boundary.

  3. Implement optimistic updates for interactive features — Show the expected result immediately while the API call runs in the background. Roll back on failure with clear error messaging. This makes applications feel instant even with 200ms API latency.

  4. Colocate related code across the stack — Keep the API route, database query, and frontend component for a feature in the same directory when your framework supports it. This makes features easy to find, modify, and delete as a unit.

  5. Cache aggressively on the server, invalidate precisely — Use HTTP cache headers for static assets (immutable, long max-age). Cache database query results with short TTLs. Invalidate specific cache keys when data changes rather than flushing entire caches.

Common Issues

N+1 query problems across API endpoints — A list endpoint fetches users, then each user's posts individually. Use eager loading (Prisma include, SQL JOINs) for known relationships. Implement DataLoader for GraphQL to batch and deduplicate requests.

Authentication state inconsistent between client and server — Token expiration causes the client to think the user is logged in while the server rejects requests. Handle 401 responses globally: redirect to login, refresh the token, or show a re-authentication prompt.

Frontend and backend type definitions drift apart — Manual type duplication inevitably diverges. Generate frontend types from the API schema (OpenAPI generator, tRPC inference, GraphQL codegen). A single source of truth eliminates an entire category of integration bugs.

Community

Reviews

Write a review

No reviews yet. Be the first to review this template!

Similar Templates