Skip to content

Latest commit

 

History

History
223 lines (164 loc) · 5.38 KB

backend-rules.md

File metadata and controls

223 lines (164 loc) · 5.38 KB
Error in user YAML: (<unknown>): did not find expected '-' indicator while parsing a block collection at line 3 column 3
---
description: Standards for building backends with the Apso platform
globs:
  - "**/*.ts"
  - "**/*.tsx"
  - "src/autogen/**"
  - "src/extensions/**"
  - ".apsorc"
  - "docker-compose.yml"
  alwaysApply: true
---

Rule: Backend Development with Apso

This rule defines how to structure, scaffold, and extend backend services using the Apso platform, a schema-first backend generation tool that produces scalable, typed REST APIs on PostgreSQL with TypeScript and NestJS.


🔧 Key Concepts

  • Apso CLI: @apso/cli — generates typed entities, services, controllers, and OpenAPI docs from a single .apsorc schema file.
  • PostgreSQL: Used as the primary relational database for structured application data.
  • NestJS: Used as the backend application framework.
  • Extensibility: All business logic and custom endpoints live outside the generated code in the src/extensions/ directory.

🚀 Apso CLI Usage

Installation

Install globally or run via npx:

npm install -g @apso/cli
# OR
npx @apso/cli --help

NPM package: https://www.npmjs.com/package/@apso/cli


CLI Commands

# Clean previously generated files
rm -rf src/autogen/*

# Scaffold API from schema
npx apso server scaffold

# Validate build
npm run build

🧬 .apsorc Schema Format

Use version 2 format only:

{
  "version": 2,
  "rootFolder": "src",
  "entities": [...],
  "relationships": [...]
}

Schema Guidelines

  • Use ManyToOne relationships for clear ownership.

  • Define to_name to disambiguate relationships.

  • Add field-level rules:

    • length, nullable, unique, default, etc.
  • Model createdBy and workspaceId for multi-tenant systems.

  • Avoid:

    • Bidirectional relationships
    • Complex ManyToMany (use join entities)

🗂️ Project Structure

src/
├── autogen/       # DO NOT MODIFY – Generated by Apso
├── extensions/    # Custom service/controller overrides
│   └── EntityName/
│       ├── EntityName.service.ts
│       └── EntityName.controller.ts
├── config/        # App + DB configuration
.apsorc            # Apso entity + relationship schema
docker-compose.yml # Local Postgres setup

🛠️ Extension Pattern

Custom logic must be added via extensions:

// src/extensions/User/User.service.ts
import { Injectable } from '@nestjs/common';
import { UserService as AutogenUserService } from '../../autogen/User/User.service';

@Injectable()
export class UserService extends AutogenUserService {
  // Add your custom methods here
}

Use the same structure for controller extensions if needed.


🔐 Secrets & Config

  • Use .env for local secrets; never commit them.
  • Use AWS Secrets Manager or Vault for production secrets.
  • Store DB credentials separately from application config.

🧪 Testing & Validation

  • Ensure build success: npm run build

  • Use Swagger UI to validate and explore generated APIs

  • Add tests for:

    • Custom services/controllers
    • Schema validation
    • Multi-tenant access control
    • Integration logic

✅ Do

  • Use @apso/cli for all entity and API generation
  • Separate custom logic into extensions/
  • Version .apsorc updates with source control
  • Keep database schema normalized
  • Add tests for all custom extensions

❌ Don't

  • Edit src/autogen/ directly
  • Store secrets in code
  • Create circular or bidirectional relationships
  • Use raw SQL unless required for optimization
  • Commit .env files or Postgres credentials

🚫 Relationship Definition Anti-Patterns

When defining relationships in .apsorc, DO NOT add these unnecessary fields that the CLI ignores:

❌ Don't Add These Fields (They're Ignored by CLI)

{
  "relationships": [
    {
      "name": "ListingToListingAgent",        // ❌ NOT USED
      "type": "ManyToOne",
      "from": "Listing",
      "to": "Agent",
      "fromField": "listingAgentId",          // ❌ NOT USED
      "toField": "id",                        // ❌ NOT USED
      "to_name": "listingAgent"
    }
  ]
}

✅ Use This Simplified Format Instead

{
  "relationships": [
    {
      "type": "ManyToOne",
      "from": "Listing",
      "to": "Agent",
      "to_name": "listingAgent"
    }
  ]
}

What the CLI Actually Uses

The CLI only processes these relationship properties:

  • from - source entity
  • to - target entity
  • type - relationship type (ManyToOne, OneToMany, ManyToMany, OneToOne)
  • to_name - custom property name (optional)
  • nullable - whether relationship is nullable (optional)
  • bi_directional - for bidirectional relationships (optional)
  • cascadeDelete - for cascade delete (optional)
  • index - for indexing (optional)
  • joinTableName, joinColumnName, inverseJoinColumnName - for ManyToMany customizations (optional)

What the CLI Automatically Generates

The CLI will automatically:

  • Generate foreign key column names (e.g., listingAgentId from to_name: "listingAgent")
  • Create proper TypeORM decorators and TypeScript types
  • Handle join table configurations for ManyToMany relationships
  • Generate inverse relationships for bidirectional setups

This rules file standardizes backend development with Apso and ensures clarity, safety, and scalability across contributors and automation agents.