Alpha inicial — não use em produção

Comandos explicados

Na ordem que você vai usar.

A documentação mostra como usar. Aqui a gente mostra o que acontece quando você aperta enter — na sequência real: banco, migration, API, servidor.

Como ler esta página

Cada comando tem três blocos:

  • O comando — o que você digita
  • O que ele faz — passo a passo do que rola por baixo
  • O que ele cria — arquivos e pastas gerados

A seção "Do zero ao CRUD" segue a ordem real do README. Siga de cima pra baixo e você tem uma API rodando.

Alpha inicial. As APIs vão mudar sem aviso prévio. Use por sua conta e risco.

🚧 Versão Alpha. O DarkStar ainda está em desenvolvimento ativo. Funcionalidades podem ser adicionadas, alteradas ou removidas sem aviso prévio. Não recomendamos uso em produção até o lançamento da versão estável. Reporte bugs e sugestões no repositório oficial.

1 Criar o banco

db:create

O comando:

darkstar forge db:create

O que ele faz:

  1. Lê as credenciais do .env
  2. Conecta ao servidor do banco (sem escolher database)
  3. Cria o banco com o nome definido no .env
  4. Não cria tabelas — só o banco vazio

Só serve pra primeira vez. Depois disso, use db:migrate.

2 Desenhar a tabela

make:migration

O comando:

darkstar forge make:migration CreateUsersTable

O que ele faz:

  1. Cria um arquivo com timestamp no nome (garante ordem de execução)
  2. Gera os métodos up() e down()
  3. Você preenche as colunas dentro do up()

O que ele cria:

database/migrations/20260103120000_CreateUsersTable.ts

Exemplo do arquivo gerado:

import { Schema, Blueprint, Connection } from '@darkstar-cli/orm'

export async function up() {
  const schema = new Schema(Connection.get())

  await schema.create('users', (table: Blueprint) => {
    table.id()
    table.string('name')
    table.string('email').unique()
    table.string('password')
    table.boolean('active').default(true)
    table.timestamps()
  })
}

export async function down() {
  const schema = new Schema(Connection.get())
  await schema.drop('users')
}

O schema builder é MySQL/MariaDB apenas. Migrations para PostgreSQL e SQLite precisam usar SQL raw dentro do up().

3 Aplicar no banco

db:migrate

O comando:

darkstar forge db:migrate

O que ele faz:

  1. Lê a tabela de controle migrations
  2. Compara com os arquivos em database/migrations/
  3. Roda só as migrations pendentes, em ordem de timestamp
  4. Registra cada uma como aplicada

Depois disso, sua tabela users existe no banco.

4 Gerar a API

make:api

O comando:

darkstar forge make:api User

O que ele faz:

  1. Cria o Model User.ts
  2. Cria o Controller com os 5 métodos REST (index, show, store, update, destroy)
  3. Cria o Service com a lógica de orquestração
  4. Cria o Repository com o acesso ao banco
  5. Cria o Schema (stub vazio — integre Zod ou Joi depois)
  6. Cria o Middleware da entidade
  7. Registra as rotas CRUD em routes/

O que ele cria:

src/
├── controllers/UserController.ts
├── services/UserService.ts
├── repositories/UserRepository.ts
├── models/User.ts
├── schemas/UserSchema.ts
├── middlewares/UserMiddleware.ts
└── routes/user.routes.ts

Exemplo do UserController.ts gerado:

import { DarkstarRequest, DarkstarResponse } from '@darkstar-cli/core'
import { UserService } from '../services/UserService'

export class UserController {
  constructor(private userService: UserService) {}

  async index(req: DarkstarRequest, res: DarkstarResponse) {
    const data = await this.userService.findAll()
    return res.ok(data)
  }

  async show(req: DarkstarRequest, res: DarkstarResponse) {
    const data = await this.userService.findById(req.param('id')!)
    if (!data) return res.notFound('User não encontrado')
    return res.ok(data)
  }

  async store(req: DarkstarRequest, res: DarkstarResponse) {
    const data = await this.userService.create(req.all())
    return res.created(data)
  }

  async update(req: DarkstarRequest, res: DarkstarResponse) {
    const data = await this.userService.update(req.param('id')!, req.all())
    return res.ok(data)
  }

  async destroy(req: DarkstarRequest, res: DarkstarResponse) {
    await this.userService.delete(req.param('id')!)
    return res.noContent()
  }
}

É o comando matador. Em 1 segundo você tem toda a cadeia MVC pronta pra editar.

5 Gerar o seeder

make:seeder

O comando:

darkstar forge make:seeder User

O que ele faz:

  1. Cria UserSeeder.ts
  2. Lê os campos da migration automaticamente
  3. Gera um run() pronto pra você popular
  4. Registra o seeder no DatabaseSeeder.ts

O que ele cria:

database/seeders/UserSeeder.ts

Exemplo do arquivo gerado:

import { User } from '../../src/models/User'

export async function run() {
  await User.create({
    name: 'teste',
    email: 'teste@email.com',
    password: 'senha123'
  })
}

E ele é registrado no DatabaseSeeder.ts:

import * as UserSeeder from './UserSeeder'

export async function run() {
  // registre seus seeders aqui
  await UserSeeder.run()
}

O auto-registro depende do comentário // registre seus seeders aqui dentro do DatabaseSeeder.ts. Se você remover ou alterar esse comentário, o seeder novo não será registrado automaticamente.

6 Popular com dados

db:seed

O comando:

darkstar forge db:seed

O que ele faz:

  1. Chama o DatabaseSeeder.ts
  2. Ele chama cada seeder na ordem definida
  3. Cada seeder insere os dados que você programou

Perfeito pra popular dados de teste após db:migrate.

7 Gerar utils

make:util

O comando:

darkstar forge make:util User

O que ele faz:

  1. Cria a pasta src/utils/user/
  2. Gera omitPassword.ts (remove o campo password de um objeto)
  3. Gera twoFactor.ts (placeholder de código 2FA)

O que ele cria:

src/utils/user/omitPassword.ts
src/utils/user/twoFactor.ts

O twoFactor.ts gerado não é compatível com RFC 6238. É só um placeholder. Para 2FA real, use otplib.

8 Gerar rate limiters

make:security

O comando:

darkstar forge make:security

O que ele faz:

  1. Cria RateLimitMiddleware.ts em src/middlewares/
  2. Gera 22 limiters prontos (auth, CRUD, upload, SSE, webhook, admin, pagamentos…)

O que ele cria:

src/middlewares/RateLimitMiddleware.ts

Como usar nas rotas:

import { loginLimiter, registerLimiter, globalLimiter } from '../middlewares/RateLimitMiddleware'

router.post('/auth/login',    loginLimiter,    ...)
router.post('/auth/register', registerLimiter, ...)
router.use('/api',            globalLimiter)
9 Subir o servidor

darkstar serve

O comando:

darkstar serve

O que ele faz:

  1. Lê o darkstar.config.ts pra saber a porta e o host
  2. Carrega as variáveis do .env
  3. Sobe o servidor HTTP (padrão: http://localhost:3000)
  4. Ativa hot-reload — salva o arquivo, o servidor reinicia
  5. Registra cada request no terminal com método, rota e status

Por baixo ele roda npm run dev. Se você renomear o script dev no package.json, darkstar serve quebra.

10 Testar

Acessar a rota

Com o servidor rodando, abra o navegador ou use curl:

GET http://localhost:3000/api/users

Resposta esperada (JSON):

[
  { "id": 1, "name": "teste",  "email": "teste@email.com" },
  { "id": 2, "name": "teste2", "email": "teste2@email.com" }
]

Se apareceu o JSON, parabéns — você acabou de subir uma API completa com o DarkStar.

Comandos avulsos

Nem tudo é passo-a-passo. Esses aqui são pra casos específicos — quando você quer só uma peça, não a API inteira.

darkstar new

O comando:

darkstar new meu-projeto

O que ele faz:

  1. Cria a pasta meu-projeto/
  2. Copia o esqueleto base do DarkStar pra dentro dela
  3. Gera o .env com as variáveis de ambiente prontas pra preencher
  4. Roda npm install automaticamente
  5. Mostra os próximos passos no terminal

O que ele cria:

meu-projeto/
├── src/
│   ├── controllers/
│   ├── services/
│   ├── repositories/
│   ├── models/
│   ├── routes/
│   ├── schemas/
│   ├── middlewares/
│   ├── utils/
│   └── core/
│       └── app.ts
├── database/
│   ├── migrations/
│   └── seeders/
│       ├── Seeder.ts
│       └── DatabaseSeeder.ts
├── .env
├── darkstar.config.ts
└── package.json

O new é o único comando que não precisa estar dentro de um projeto. Os outros, sim.

make:controller

O comando:

darkstar forge make:controller User

O que ele faz:

  1. Cria UserController.ts
  2. Já vem com os 5 métodos REST esqueleto
  3. Injeta o UserService no construtor
  4. Não cria Service, Repository, Model nem rotas

O que ele cria:

src/controllers/UserController.ts

make:service

O comando:

darkstar forge make:service User

O que ele faz:

  1. Cria UserService.ts
  2. Já vem com os métodos findAll, findById, create, update, delete
  3. Injeta o UserRepository no construtor

O que ele cria:

src/services/UserService.ts

make:repository

O comando:

darkstar forge make:repository User

O que ele faz:

  1. Cria UserRepository.ts
  2. Importa o User model
  3. Já traz as 5 operações CRUD mapeadas pro Query Builder

O que ele cria:

src/repositories/UserRepository.ts

O Repository é a única camada que fala com o banco. Trocar de ORM = só editar aqui.

make:schema

O comando:

darkstar forge make:schema User

Exemplo com Zod (integração manual):

import { z } from 'zod'

export const UserSchema = z.object({
  name:     z.string().min(1),
  email:    z.string().email(),
  password: z.string().min(6)
})

⚠️ JWT não vem incluso no DarkStar. Para autenticação com JWT, instale a biblioteca separadamente:

npm install zod jsonwebtoken
npm install -D @types/jsonwebtoken

make:middleware

O comando:

darkstar forge make:middleware User

Exemplo do stub gerado:

import { DarkstarRequest, DarkstarResponse, NextFunction } from '@darkstar-cli/core'

export class UserMiddleware {
  handle(req: DarkstarRequest, res: DarkstarResponse, next: NextFunction) {
    next()
  }
}

db:rollback

O comando:

darkstar forge db:rollback

O que ele faz:

  1. Descobre qual foi a última migration aplicada
  2. Roda o método down() dela
  3. Remove o registro da tabela de controle

Desfaz uma por vez. Rode várias vezes pra voltar várias.

ORM — Referência rápida

Model

import { Model } from '@darkstar-cli/orm'

export class User extends Model {
  static table = 'users'
}

QueryBuilder

const users = await User.query().where('active', true).orderBy('created_at', 'desc').limit(10).get()
const user  = await User.query().where('email', 'teste@email.com').first()
const total = await User.query().where('role', 'admin').count()

Blueprint

import { Schema, Blueprint, Connection } from '@darkstar-cli/orm'

const schema = new Schema(Connection.get())

await schema.create('users', (table: Blueprint) => {
  table.id()
  table.string('name')
  table.string('email').unique()
  table.string('password')
  table.boolean('active').default(true)
  table.timestamps()
})

Schema

import { Schema, Connection } from '@darkstar-cli/orm'

const schema = new Schema(Connection.get())

await schema.create('products', (table) => { ... })
await schema.drop('products')
const existe = await schema.hasTable('products')

Drivers suportados

DriverDB_CONNECTIONDependência
MySQLmysqlmysql2
MariaDBmariadbmysql2
PostgreSQLpostgrespg
SQLitesqlitebetter-sqlite3

Fluxo de uma request

Request
Rota
Controller
Service
Repository
Banco

Convenção, não magia

User → users é pluralização automática.
UserController é sempre injetado com UserService.
UserService é sempre injetado com UserRepository.
make:api User gera tudo porque sabe a convenção.