agentsclimarketplace

Senior fullstack

Skill roedyrustam/claudevibeskills/src/senior-fullstack

Koleksi 20 Claude Skills siap pakai untuk pengembangan SaaS, web modern, dan praktik rekayasa perangkat lunak tingkat lanjut.

Install
npx -y skills add roedyrustam/claudevibeskills --skill senior-fullstack

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Expert fullstack architecture skill covering advanced backend patterns, infrastructure, testing, and system design. Use this skill whenever the user is working on fullstack architecture decisions, API design, background job queues, caching strategies, database connection pooling, CI/CD pipelines, Docker containerization, end-to-end testing with Playwright, WebSocket real-time features, or deployment configurations. Trigger on mentions of Redis, BullMQ, Prisma, Drizzle, PostgreSQL, Docker, GitHub Actions, connection pooling, rate limiting, Playwright, or any backend/infra topic that goes beyond simple CRUD. Also trigger for performance bottlenecks, scalability concerns, or production readiness reviews.

SKILL.md

16.3 KB, as published. Nobody here has run it

Senior Fullstack Engineer Skill

Advanced architectural patterns, infrastructure, testing, and production-grade system design.


Core Stack

LayerTechnology
FrameworkNext.js 15 (App Router)
ORMDrizzle ORM or Prisma
DatabasePostgreSQL (Supabase / Neon / RDS)
Cache / QueueRedis + BullMQ
AuthClerk or NextAuth v5
PaymentsStripe
TestingPlaywright (E2E) + Vitest (unit)
CI/CDGitHub Actions
ContainersDocker + Docker Compose
MonitoringSentry + OpenTelemetry

Database Layer

Drizzle ORM (Preferred — Type-Safe, Lightweight)

// lib/db/schema.ts
import { pgTable, text, timestamp, uuid, boolean, index } from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
  id: uuid('id').primaryKey().defaultRandom(),
  clerkId: text('clerk_id').notNull().unique(),
  email: text('email').notNull().unique(),
  name: text('name').notNull(),
  createdAt: timestamp('created_at').notNull().defaultNow(),
  updatedAt: timestamp('updated_at').notNull().defaultNow(),
}, (table) => ({
  clerkIdIdx: index('users_clerk_id_idx').on(table.clerkId),
  emailIdx: index('users_email_idx').on(table.email),
}))

export const posts = pgTable('posts', {
  id: uuid('id').primaryKey().defaultRandom(),
  userId: uuid('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
  title: text('title').notNull(),
  slug: text('slug').notNull().unique(),
  content: text('content'),
  published: boolean('published').notNull().default(false),
  publishedAt: timestamp('published_at'),
  createdAt: timestamp('created_at').notNull().defaultNow(),
}, (table) => ({
  userIdIdx: index('posts_user_id_idx').on(table.userId),
  slugIdx: index('posts_slug_idx').on(table.slug),
}))

Database Connection Pooling

// lib/db/index.ts
import { drizzle } from 'drizzle-orm/node-postgres'
import { Pool } from 'pg'
import * as schema from './schema'

// Single pool instance — critical for connection pooling
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  max: 20,                    // Max connections
  idleTimeoutMillis: 30_000,  // Close idle connections after 30s
  connectionTimeoutMillis: 2_000,
})

export const db = drizzle(pool, { schema })

// For serverless (Neon, Supabase with pgBouncer)
// Use neon-serverless driver instead:
// import { neon } from '@neondatabase/serverless'
// const sql = neon(process.env.DATABASE_URL!)
// export const db = drizzle(sql, { schema })

Repository Pattern

// lib/db/repositories/post.repository.ts
import { db } from '@/lib/db'
import { posts, users } from '@/lib/db/schema'
import { eq, desc, and, sql } from 'drizzle-orm'

export class PostRepository {
  async findPublished(limit = 10, offset = 0) {
    return db
      .select({
        id: posts.id,
        title: posts.title,
        slug: posts.slug,
        publishedAt: posts.publishedAt,
        author: { name: users.name },
      })
      .from(posts)
      .innerJoin(users, eq(posts.userId, users.id))
      .where(eq(posts.published, true))
      .orderBy(desc(posts.publishedAt))
      .limit(limit)
      .offset(offset)
  }

  async findBySlug(slug: string) {
    const [post] = await db
      .select()
      .from(posts)
      .where(eq(posts.slug, slug))
      .limit(1)
    return post ?? null
  }

  async create(data: typeof posts.$inferInsert) {
    const [post] = await db.insert(posts).values(data).returning()
    return post
  }

  async incrementView(id: string) {
    await db
      .update(posts)
      .set({ viewCount: sql`${posts.viewCount} + 1` })
      .where(eq(posts.id, id))
  }
}

export const postRepository = new PostRepository()

Redis Caching

Setup & Client

// lib/redis.ts
import { Redis } from 'ioredis'

let redis: Redis

if (process.env.NODE_ENV === 'production') {
  redis = new Redis(process.env.REDIS_URL!, {
    maxRetriesPerRequest: 3,
    enableReadyCheck: false,
    lazyConnect: true,
  })
} else {
  // Singleton in dev to prevent hot-reload creating new connections
  const globalForRedis = globalThis as { redis?: Redis }
  globalForRedis.redis ??= new Redis(process.env.REDIS_URL!)
  redis = globalForRedis.redis
}

export { redis }

Cache-Aside Pattern

// lib/cache.ts
import { redis } from './redis'

export async function cached<T>(
  key: string,
  fn: () => Promise<T>,
  ttlSeconds = 60
): Promise<T> {
  const cached = await redis.get(key)
  if (cached) return JSON.parse(cached) as T

  const result = await fn()
  await redis.setex(key, ttlSeconds, JSON.stringify(result))
  return result
}

export function cacheKey(...parts: string[]) {
  return parts.join(':')
}

// Usage
const posts = await cached(
  cacheKey('posts', 'published', page.toString()),
  () => postRepository.findPublished(10, offset),
  300 // 5 minutes
)

Cache Invalidation Strategy

// Granular tag-based invalidation
export async function invalidatePostCache(postId: string, slug: string) {
  const keys = await redis.keys(`posts:*`)
  if (keys.length > 0) await redis.del(...keys)
  await redis.del(`post:${slug}`, `post:${postId}`)
}

Background Jobs with BullMQ

Queue Setup

// lib/queues/index.ts
import { Queue, Worker, QueueEvents } from 'bullmq'
import { redis } from '@/lib/redis'

const connection = { connection: redis }

// Define queues
export const emailQueue = new Queue('email', connection)
export const imageQueue = new Queue('image-processing', connection)
export const webhookQueue = new Queue('webhooks', connection)

// Job types
export type EmailJobData = {
  to: string
  subject: string
  template: 'welcome' | 'reset-password' | 'invoice'
  variables: Record<string, string>
}

Worker

// workers/email.worker.ts
import { Worker } from 'bullmq'
import { redis } from '@/lib/redis'
import { sendEmail } from '@/lib/email'
import type { EmailJobData } from '@/lib/queues'

export const emailWorker = new Worker<EmailJobData>(
  'email',
  async (job) => {
    const { to, subject, template, variables } = job.data

    await job.updateProgress(10)

    const html = await renderEmailTemplate(template, variables)

    await job.updateProgress(50)

    await sendEmail({ to, subject, html })

    await job.updateProgress(100)

    return { sent: true, to }
  },
  {
    connection: { connection: redis },
    concurrency: 5,
    limiter: { max: 100, duration: 60_000 }, // 100 emails/min
  }
)

emailWorker.on('completed', (job, result) => {
  console.log(`Email job ${job.id} completed`, result)
})

emailWorker.on('failed', (job, err) => {
  console.error(`Email job ${job?.id} failed:`, err)
})

Enqueue from Server Actions

// app/actions/auth.actions.ts
'use server'
import { emailQueue } from '@/lib/queues'

export async function sendWelcomeEmail(userId: string) {
  const user = await userRepository.findById(userId)
  if (!user) return

  await emailQueue.add(
    'welcome-email',
    {
      to: user.email,
      subject: 'Welcome!',
      template: 'welcome',
      variables: { name: user.name },
    },
    {
      attempts: 3,
      backoff: { type: 'exponential', delay: 5000 },
      removeOnComplete: 100,  // Keep last 100 completed
      removeOnFail: 500,
    }
  )
}

API Design (Route Handlers)

Typed Route Handler

// app/api/posts/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { auth } from '@clerk/nextjs/server'
import { z } from 'zod'
import { postRepository } from '@/lib/db/repositories/post.repository'

const createPostSchema = z.object({
  title: z.string().min(1).max(200),
  content: z.string().optional(),
  published: z.boolean().default(false),
})

export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url)
  const page = Math.max(1, Number(searchParams.get('page') ?? 1))
  const limit = Math.min(50, Number(searchParams.get('limit') ?? 10))

  const posts = await postRepository.findPublished(limit, (page - 1) * limit)
  return NextResponse.json({ data: posts, page, limit })
}

export async function POST(request: NextRequest) {
  const { userId } = await auth()
  if (!userId) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
  }

  const body = await request.json()
  const parsed = createPostSchema.safeParse(body)
  if (!parsed.success) {
    return NextResponse.json(
      { error: 'Validation failed', details: parsed.error.flatten() },
      { status: 422 }
    )
  }

  const post = await postRepository.create({ ...parsed.data, userId })
  return NextResponse.json({ data: post }, { status: 201 })
}

Rate Limiting Middleware

// middleware.ts
import { NextResponse, type NextRequest } from 'next/server'
import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis'

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(10, '10 s'),
  analytics: true,
})

export async function middleware(request: NextRequest) {
  if (request.nextUrl.pathname.startsWith('/api/')) {
    const ip = request.ip ?? '127.0.0.1'
    const { success, limit, reset, remaining } = await ratelimit.limit(ip)

    if (!success) {
      return NextResponse.json(
        { error: 'Too many requests' },
        {
          status: 429,
          headers: {
            'X-RateLimit-Limit': limit.toString(),
            'X-RateLimit-Remaining': remaining.toString(),
            'X-RateLimit-Reset': reset.toString(),
          },
        }
      )
    }
  }
}

export const config = {
  matcher: '/api/:path*',
}

Testing

Playwright E2E

// tests/e2e/auth.spec.ts
import { test, expect } from '@playwright/test'

test.describe('Authentication flow', () => {
  test('user can sign up and access dashboard', async ({ page }) => {
    await page.goto('/sign-up')

    await page.fill('[name="email"]', '[email protected]')
    await page.fill('[name="password"]', 'SecurePass123!')
    await page.click('[type="submit"]')

    await expect(page).toHaveURL('/dashboard')
    await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible()
  })

  test('protected routes redirect unauthenticated users', async ({ page }) => {
    await page.goto('/dashboard')
    await expect(page).toHaveURL(/\/sign-in/)
  })
})
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test'

export default defineConfig({
  testDir: './tests/e2e',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: [['html'], ['github']],
  use: {
    baseURL: process.env.BASE_URL ?? 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'Mobile Safari', use: { ...devices['iPhone 14'] } },
  ],
  webServer: {
    command: 'pnpm dev',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
  },
})

Vitest Unit Tests

// lib/__tests__/cache.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { cached } from '@/lib/cache'

vi.mock('@/lib/redis', () => ({
  redis: {
    get: vi.fn(),
    setex: vi.fn(),
  },
}))

describe('cached()', () => {
  beforeEach(() => vi.clearAllMocks())

  it('returns cached value when cache hit', async () => {
    const { redis } = await import('@/lib/redis')
    vi.mocked(redis.get).mockResolvedValue(JSON.stringify({ id: 1 }))

    const fn = vi.fn().mockResolvedValue({ id: 1 })
    const result = await cached('test-key', fn)

    expect(result).toEqual({ id: 1 })
    expect(fn).not.toHaveBeenCalled()
  })

  it('calls fn and caches result on miss', async () => {
    const { redis } = await import('@/lib/redis')
    vi.mocked(redis.get).mockResolvedValue(null)

    const fn = vi.fn().mockResolvedValue({ id: 2 })
    const result = await cached('test-key', fn, 60)

    expect(result).toEqual({ id: 2 })
    expect(redis.setex).toHaveBeenCalledWith('test-key', 60, JSON.stringify({ id: 2 }))
  })
})

Docker & CI/CD

Multi-Stage Dockerfile

# Dockerfile
FROM node:20-alpine AS base
RUN apk add --no-cache libc6-compat
WORKDIR /app
RUN npm install -g pnpm

FROM base AS deps
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile

FROM base AS builder
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN pnpm build

FROM base AS runner
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

CMD ["node", "server.js"]

GitHub Actions CI Pipeline

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: testdb
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432

    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v3
        with:
          version: 9
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Type check
        run: pnpm tsc --noEmit

      - name: Lint
        run: pnpm lint

      - name: Unit tests
        run: pnpm test
        env:
          DATABASE_URL: postgresql://postgres:postgres@localhost:5432/testdb

      - name: Run migrations
        run: pnpm db:migrate
        env:
          DATABASE_URL: postgresql://postgres:postgres@localhost:5432/testdb

      - name: Build
        run: pnpm build
        env:
          DATABASE_URL: postgresql://postgres:postgres@localhost:5432/testdb

  e2e:
    runs-on: ubuntu-latest
    needs: test
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v3
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile
      - name: Install Playwright browsers
        run: pnpm playwright install --with-deps chromium
      - name: Run E2E tests
        run: pnpm playwright test
        env:
          BASE_URL: http://localhost:3000
      - uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: playwright-report
          path: playwright-report/

Key Architectural Rules

  1. Repository pattern for all DB access — never raw queries in route handlers or Server Actions
  2. Connection pool as singleton — one Pool instance, not one per request
  3. BullMQ for anything async — email, image processing, webhooks, notifications
  4. Redis cache-aside — cache at the repository layer, not the component layer
  5. Zod validation at every API boundary — route handlers AND Server Actions
  6. Rate limit all public APIs — use Upstash Redis for serverless-safe limiting
  7. Multi-stage Docker builds — never ship dev dependencies to production
  8. Test pyramid: unit (Vitest) > integration > E2E (Playwright)
  9. CI gates on type check + lint + unit tests before E2E
  10. Never commit secrets — use environment variables, validate at startup

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.