backend-bootstrapper

Bootstraps complete backend with Apso, including API setup, database configuration, and testing. Triggers when user needs to create backend, setup API, or initialize server.

$ 설치

git clone https://github.com/mavric/devenv /tmp/devenv && cp -r /tmp/devenv/install/.claude/skills/backend-bootstrapper ~/.claude/skills/devenv

// tip: Run this command in your terminal to install the skill


name: backend-bootstrapper description: Bootstraps complete backend with Apso, including API setup, database configuration, and testing. Triggers when user needs to create backend, setup API, or initialize server.

Backend Bootstrapper

I set up production-ready backends using Apso, giving you a fully functional REST API in minutes.

What I Create

1. Apso Service Configuration

Complete .apsorc schema file with:

  • All entities defined
  • Relationships configured
  • Validation rules
  • Indexes optimized
  • Multi-tenancy enabled

2. Generated NestJS Backend

Apso auto-generates:

  • REST API with OpenAPI docs
  • CRUD endpoints for all entities
  • TypeORM models
  • Database migrations
  • Validation middleware
  • Error handling
  • Logging

3. Database Setup

  • PostgreSQL database (local or AWS RDS)
  • All tables created
  • Relationships enforced
  • Migrations ready
  • Seed data (optional)

4. Development Environment

  • Docker Compose for local database
  • Environment variable configuration
  • Development server running
  • Hot reload enabled

5. API Documentation

  • OpenAPI/Swagger documentation
  • Interactive API testing UI
  • Type definitions exported
  • Example requests

The Bootstrap Process

Step 1: Validate Schema

I'll review the schema from schema-architect and:

  • Check for missing fields
  • Validate relationships
  • Ensure multi-tenancy
  • Add recommended indexes
  • Suggest optimizations

Step 2: Create Apso Project

# Install Apso CLI
npm install -g @apso/apso-cli

# Create new service
apso server new --name your-service-backend

# Navigate to project
cd your-service-backend

Step 3: Configure Schema

I'll create the .apsorc file with your entities:

{
  "service": "your-service-api",
  "version": "1.0.0",
  "database": {
    "provider": "postgresql",
    "host": "localhost",
    "port": 5432,
    "database": "your_service_db"
  },
  "auth": {
    "enabled": true,
    "provider": "better-auth"
  },
  "multiTenant": true,
  "entities": {
    // Your schema here
  }
}

Step 4: Generate Code

# Generate NestJS backend
apso server scaffold

# This creates:
# src/
#   autogen/        ← Generated code (DON'T EDIT)
#   extensions/     ← Your custom code
#   common/         ← Shared utilities
#   main.ts         ← Entry point

Step 5: Install Dependencies

npm install

Step 6: Start Database

# Start PostgreSQL via Docker
npm run compose

# This starts:
# - PostgreSQL on port 5432
# - pgAdmin on port 5050 (optional)

Step 7: Provision Database

# Create tables and run migrations
npm run provision

# This:
# - Creates all tables
# - Sets up foreign keys
# - Creates indexes
# - Runs seed data (if any)

Step 8: Start Development Server

# Start backend server
npm run start:dev

# Server runs at:
# - API: http://localhost:3001
# - OpenAPI Docs: http://localhost:3001/api/docs
# - Health Check: http://localhost:3001/health

Step 9: Verify & Test

I'll test all endpoints:

# Health check
curl http://localhost:3001/health

# Test CRUD endpoints
curl http://localhost:3001/organizations
curl http://localhost:3001/users
curl http://localhost:3001/projects

Generated API Structure

For each entity, you get:

Standard REST Endpoints

List

GET /entities
Query params: ?page=1&limit=10&sort=created_at&order=desc
Response: { data: [...], total: 100, page: 1, limit: 10 }

Get by ID

GET /entities/:id
Response: { id, ...fields }

Create

POST /entities
Body: { field1: value1, field2: value2 }
Response: { id, ...fields, created_at, updated_at }

Update

PUT /entities/:id
PATCH /entities/:id  (partial update)
Body: { field1: newValue }
Response: { id, ...fields, updated_at }

Delete

DELETE /entities/:id
Response: { success: true }

Filtering & Querying

Filter by field

GET /entities?status=active
GET /entities?created_at_gte=2024-01-01

Full-text search

GET /entities?search=keyword

Relations

GET /entities?include=relations
GET /organizations/123/users  (nested route)

Aggregations

GET /entities/count
GET /entities/stats

Automatic Features

1. Multi-Tenancy

Every request is automatically scoped to the organization:

// Middleware adds organization context
@UseGuards(OrgGuard)
export class ProjectController {
  // All queries filtered by req.organizationId
  async findAll(@Req() req) {
    // Only returns projects for req.organizationId
  }
}

2. Validation

Input validation with class-validator:

// Automatically validated
class CreateProjectDto {
  @IsString()
  @MinLength(3)
  @MaxLength(100)
  name: string;

  @IsEnum(['active', 'archived'])
  status: string;
}

3. Error Handling

Consistent error responses:

{
  "statusCode": 400,
  "message": "Validation failed",
  "errors": [
    {
      "field": "name",
      "message": "name must be at least 3 characters"
    }
  ]
}

4. Logging

Structured logging with Winston:

// Automatic logging of:
// - All requests
// - Errors
// - Database queries
// - Performance metrics

5. OpenAPI Documentation

Interactive docs at /api/docs:

  • All endpoints documented
  • Request/response schemas
  • Try-it-out functionality
  • Example requests

File Structure

your-service-backend/
├── src/
│   ├── autogen/              ← ⚠️ NEVER MODIFY - Generated by Apso
│   │   ├── Organization/     ← Entity-specific modules
│   │   │   ├── Organization.entity.ts
│   │   │   ├── Organization.service.ts
│   │   │   ├── Organization.controller.ts
│   │   │   └── Organization.module.ts
│   │   ├── User/
│   │   ├── guards/           ← ⚠️ AUTO-GENERATED - Auth & scope guards
│   │   │   ├── auth.guard.ts     # AuthGuard for session validation
│   │   │   ├── scope.guard.ts    # ScopeGuard for multi-tenant data isolation
│   │   │   ├── guards.module.ts  # NestJS module for guards
│   │   │   └── index.ts          # Barrel exports
│   │   └── index.ts
│   │
│   ├── extensions/           ← ✅ YOUR CUSTOM CODE (safe to modify)
│   │   ├── Organization/
│   │   │   ├── Organization.controller.ts   (add custom endpoints)
│   │   │   └── Organization.service.ts      (add business logic)
│   │   ├── User/
│   │   ├── Project/
│   │   └── auth/             (Better Auth integration)
│   │
│   ├── common/               ← Shared utilities
│   │   ├── interceptors/
│   │   ├── decorators/
│   │   └── filters/
│   │
│   └── main.ts               ← App entry point
│
├── test/                     ← Tests
│   ├── unit/
│   └── e2e/
│
├── .apsorc                   ← Schema definition
├── docker-compose.yml        ← Local database
├── package.json
└── README.md

Important: Guards are now generated inside src/autogen/guards/ to clearly indicate they are auto-generated. All files in autogen/ are overwritten on every apso server scaffold run.

Customization Options

Adding Custom Endpoints

// src/extensions/Project/Project.controller.ts
import { Controller, Post, Param } from '@nestjs/common';

@Controller('projects')
export class ProjectController {
  // Add custom endpoint
  @Post(':id/archive')
  async archive(@Param('id') id: string) {
    // Your custom logic
    return this.projectService.archive(id);
  }

  @Get(':id/statistics')
  async getStats(@Param('id') id: string) {
    // Custom aggregation
    return this.projectService.getStatistics(id);
  }
}

Adding Business Logic

// src/extensions/Project/Project.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class ProjectService {
  async archive(id: string) {
    // Complex business logic
    const project = await this.findOne(id);

    // Archive all tasks
    await this.taskService.archiveByProject(id);

    // Update project status
    return this.update(id, { status: 'archived' });
  }
}

Adding Middleware

// src/common/interceptors/logging.interceptor.ts
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler) {
    const req = context.switchToHttp().getRequest();
    const { method, url } = req;

    console.log(`${method} ${url}`);

    return next.handle();
  }
}

Environment Configuration

I'll create .env files:

# .env (local development)
NODE_ENV=development
PORT=3001

# Database
DB_HOST=localhost
DB_PORT=5432
DB_NAME=your_service_db
DB_USER=postgres
DB_PASSWORD=postgres

# Better Auth
AUTH_SECRET=your-secret-key-here
AUTH_URL=http://localhost:3001

# AWS (for production)
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=

# Stripe
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...

Testing

I'll set up testing structure:

// test/e2e/project.e2e-spec.ts
describe('ProjectController (e2e)', () => {
  let app: INestApplication;

  beforeEach(async () => {
    const moduleFixture = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  it('/projects (GET)', () => {
    return request(app.getHttpServer())
      .get('/projects')
      .expect(200)
      .expect((res) => {
        expect(res.body.data).toBeInstanceOf(Array);
      });
  });

  it('/projects (POST)', () => {
    return request(app.getHttpServer())
      .post('/projects')
      .send({ name: 'Test Project', organization_id: '...' })
      .expect(201)
      .expect((res) => {
        expect(res.body.name).toBe('Test Project');
      });
  });
});

Verification Checklist

Before marking bootstrap as complete, I verify:

  • ✅ Server starts without errors
  • ✅ Database connection successful
  • ✅ All tables created
  • ✅ OpenAPI docs accessible
  • ✅ CRUD endpoints work for all entities
  • ✅ Multi-tenancy filtering active
  • ✅ Validation works on create/update
  • ✅ Error handling returns proper responses
  • ✅ Environment variables configured
  • ✅ Docker Compose running

Common Issues & Solutions

Issue: "Cannot connect to database" Fix: Ensure npm run compose is running and ports aren't conflicting

Issue: "Module not found" Fix: Run npm install after generating code

Issue: "TypeORM entity not found" Fix: Run npm run provision to sync schema

Issue: "Port 3001 already in use" Fix: Kill existing process: lsof -ti:3001 | xargs kill

What's Next?

After bootstrap, you're ready for:

  1. Frontend Setup - Call frontend-bootstrapper
  2. Authentication - Call auth-implementer
  3. Custom Endpoints - Add business logic to extensions/
  4. Testing - Call test-generator

Ready?

I'll bootstrap a production-ready backend in about 5 minutes. Just provide your schema (or I can call schema-architect first if you don't have one yet).

Do you have a schema ready, or should I design one first?