@riligar/agents-kit 1.20.0 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,29 +1,29 @@
1
1
  ---
2
2
  name: riligar-dev-database
3
- description: Database patterns for RiLiGar using Drizzle ORM + bun:sqlite. Use when setting up database connections, defining schemas, creating migrations, or writing queries. Covers SQLite on Fly.io volumes with the drizzle-kit workflow.
3
+ description: database patterns for RiLiGar using Drizzle ORM + bun:sqlite. Use when setting up database connections, defining schemas, creating migrations, or writing queries. Covers SQLite on Fly.io volumes with the drizzle-kit workflow.
4
4
  ---
5
5
 
6
- # Database — Drizzle + bun:sqlite
6
+ # database — Drizzle + bun:sqlite
7
7
 
8
8
  > SQLite nativo no Bun. Zero drivers externos. Base de dados no volume do Fly.io (`/app/data`).
9
9
 
10
10
  ## Referências
11
11
 
12
- | Arquivo | Quando usar |
13
- | --- | --- |
14
- | [connection.md](references/connection.md) | Setup inicial: instalação, db.js, drizzle.config |
15
- | [schema.md](references/schema.md) | Definir tabelas, tipos de colunas, relações |
16
- | [migrations.md](references/migrations.md) | Criar e executar migrations com drizzle-kit |
17
- | [queries.md](references/queries.md) | Select, insert, update, delete, queries com relações |
12
+ | Arquivo | Quando usar |
13
+ | ----------------------------------------- | ---------------------------------------------------- |
14
+ | [connection.md](references/connection.md) | Setup inicial: instalação, db.js, drizzle.config |
15
+ | [schema.md](references/schema.md) | Definir tabelas, tipos de colunas, relações |
16
+ | [migrations.md](references/migrations.md) | Criar e executar migrations com drizzle-kit |
17
+ | [queries.md](references/queries.md) | Select, insert, update, delete, queries com relações |
18
18
 
19
19
  ## Quick Start
20
20
 
21
21
  ```javascript
22
22
  // database/db.js
23
23
  import { drizzle } from 'drizzle-orm/bun-sqlite'
24
- import Database from 'bun:sqlite'
24
+ import database from 'bun:sqlite'
25
25
 
26
- const sqlite = new Database(process.env.DB_PATH ?? './data/database.db')
26
+ const sqlite = new database(process.env.DB_PATH ?? './database/database.db')
27
27
  const db = drizzle({ client: sqlite })
28
28
 
29
29
  export { db }
@@ -31,15 +31,15 @@ export { db }
31
31
 
32
32
  ## Regras
33
33
 
34
- - **Caminho do banco:** `/app/data/database.db` em produção (volume Fly.io). `./data/database.db` em desenvolvimento.
34
+ - **Caminho do banco:** `/app/data/database.db` em produção (volume Fly.io). `./database/database.db` em desenvolvimento.
35
35
  - **Migrations sempre:** Use `drizzle-kit generate` + `drizzle-kit migrate`. Nunca edite migrations à mão.
36
36
  - **Schema único:** Todas as tabelas em `database/schema.js`.
37
37
  - **Migrations no startup:** Use `migrate()` no `index.js` antes de `.listen()`.
38
38
 
39
39
  ## Related Skills
40
40
 
41
- | Need | Skill |
42
- | --- | --- |
43
- | **Backend (Elysia)** | @[.agent/skills/riligar-dev-manager] |
41
+ | Need | Skill |
42
+ | --------------------- | ------------------------------------- |
43
+ | **Backend (Elysia)** | @[.agent/skills/riligar-dev-manager] |
44
44
  | **Payments (Stripe)** | @[.agent/skills/riligar-infra-stripe] |
45
- | **Infrastructure** | @[.agent/skills/riligar-infra-fly] |
45
+ | **Infrastructure** | @[.agent/skills/riligar-infra-fly] |
@@ -1,4 +1,4 @@
1
- # Database Connection
1
+ # database Connection
2
2
 
3
3
  ## Installation
4
4
 
@@ -14,15 +14,15 @@ No additional drivers needed — `bun:sqlite` is built into Bun.
14
14
  ```javascript
15
15
  // database/db.js
16
16
  import { drizzle } from 'drizzle-orm/bun-sqlite'
17
- import Database from 'bun:sqlite'
17
+ import database from 'bun:sqlite'
18
18
 
19
- const sqlite = new Database(process.env.DB_PATH ?? './data/database.db')
19
+ const sqlite = new database(process.env.DB_PATH ?? './database/database.db')
20
20
  const db = drizzle({ client: sqlite })
21
21
 
22
22
  export { db }
23
23
  ```
24
24
 
25
- - Em **desenvolvimento**: `DB_PATH` não é definido → usa `./data/database.db`
25
+ - Em **desenvolvimento**: `DB_PATH` não é definido → usa `./database/database.db`
26
26
  - Em **produção** (Fly.io): `fly secrets set DB_PATH=/app/data/database.db`
27
27
 
28
28
  ## drizzle.config.js
@@ -36,7 +36,7 @@ export default defineConfig({
36
36
  schema: './database/schema.js',
37
37
  out: './database/migrations',
38
38
  dbCredentials: {
39
- url: process.env.DB_PATH ?? './data/database.db',
39
+ url: process.env.DB_PATH ?? './database/database.db',
40
40
  },
41
41
  })
42
42
  ```
@@ -53,9 +53,7 @@ import { db } from './database/db'
53
53
  await migrate(db, { migrationsFolder: './database/migrations' })
54
54
 
55
55
  // ... resto do setup
56
- const app = new Elysia()
57
- .use(routes)
58
- .listen(3000)
56
+ const app = new Elysia().use(routes).listen(3000)
59
57
  ```
60
58
 
61
59
  Isso garante que o banco esteja sempre atualizado quando o servidor inicia no Fly.io.
@@ -17,10 +17,12 @@ import { eq, and, or, desc, asc } from 'drizzle-orm'
17
17
  const allUsers = await db.select().from(users)
18
18
 
19
19
  // Campos específicos
20
- const names = await db.select({
21
- id: users.id,
22
- name: users.name,
23
- }).from(users)
20
+ const names = await db
21
+ .select({
22
+ id: users.id,
23
+ name: users.name,
24
+ })
25
+ .from(users)
24
26
  ```
25
27
 
26
28
  ### Filtrar
@@ -30,23 +32,24 @@ const names = await db.select({
30
32
  const [user] = await db.select().from(users).where(eq(users.id, userId)).limit(1)
31
33
 
32
34
  // Múltiplos filtros (AND)
33
- const results = await db.select().from(users).where(
34
- and(
35
- eq(users.active, true),
36
- eq(users.plan, 'pro')
37
- )
38
- )
35
+ const results = await db
36
+ .select()
37
+ .from(users)
38
+ .where(and(eq(users.active, true), eq(users.plan, 'pro')))
39
39
 
40
40
  // OR
41
- const results = await db.select().from(users).where(
42
- or(eq(users.id, '1'), eq(users.id, '2'))
43
- )
41
+ const results = await db
42
+ .select()
43
+ .from(users)
44
+ .where(or(eq(users.id, '1'), eq(users.id, '2')))
44
45
  ```
45
46
 
46
47
  ### Ordenar e Paginar
47
48
 
48
49
  ```javascript
49
- const page = await db.select().from(posts)
50
+ const page = await db
51
+ .select()
52
+ .from(posts)
50
53
  .orderBy(desc(posts.createdAt))
51
54
  .limit(10)
52
55
  .offset(pageIndex * 10)
@@ -59,9 +62,7 @@ const page = await db.select().from(posts)
59
62
  await db.insert(users).values({ name: 'Dan', email: 'dan@email.com' })
60
63
 
61
64
  // Com retorno
62
- const [user] = await db.insert(users)
63
- .values({ name: 'Dan', email: 'dan@email.com' })
64
- .returning()
65
+ const [user] = await db.insert(users).values({ name: 'Dan', email: 'dan@email.com' }).returning()
65
66
 
66
67
  // Múltiplos
67
68
  await db.insert(users).values([
@@ -70,7 +71,8 @@ await db.insert(users).values([
70
71
  ])
71
72
 
72
73
  // Upsert (conflict handling)
73
- await db.insert(users)
74
+ await db
75
+ .insert(users)
74
76
  .values({ id: '1', name: 'Dan' })
75
77
  .onConflictDoUpdate({
76
78
  target: users.id,
@@ -81,15 +83,10 @@ await db.insert(users)
81
83
  ## Update
82
84
 
83
85
  ```javascript
84
- await db.update(users)
85
- .set({ name: 'Mr. Dan', updatedAt: new Date() })
86
- .where(eq(users.id, userId))
86
+ await db.update(users).set({ name: 'Mr. Dan', updatedAt: new Date() }).where(eq(users.id, userId))
87
87
 
88
88
  // Com retorno
89
- const [updated] = await db.update(users)
90
- .set({ plan: 'pro' })
91
- .where(eq(users.id, userId))
92
- .returning()
89
+ const [updated] = await db.update(users).set({ plan: 'pro' }).where(eq(users.id, userId)).returning()
93
90
  ```
94
91
 
95
92
  ## Delete
@@ -98,9 +95,7 @@ const [updated] = await db.update(users)
98
95
  await db.delete(users).where(eq(users.id, userId))
99
96
 
100
97
  // Com retorno
101
- const [deleted] = await db.delete(users)
102
- .where(eq(users.id, userId))
103
- .returning()
98
+ const [deleted] = await db.delete(users).where(eq(users.id, userId)).returning()
104
99
  ```
105
100
 
106
101
  ## Queries com Relações
@@ -159,7 +154,8 @@ export async function createUser(data) {
159
154
  }
160
155
 
161
156
  export async function updateUser(id, data) {
162
- const [user] = await db.update(users)
157
+ const [user] = await db
158
+ .update(users)
163
159
  .set({ ...data, updatedAt: new Date() })
164
160
  .where(eq(users.id, id))
165
161
  .returning()
@@ -8,37 +8,41 @@ import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'
8
8
  import { relations } from 'drizzle-orm'
9
9
 
10
10
  export const users = sqliteTable('users', {
11
- id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
11
+ id: text('id')
12
+ .primaryKey()
13
+ .$defaultFn(() => crypto.randomUUID()),
12
14
  email: text('email').notNull().unique(),
13
15
  name: text('name'),
14
- createdAt: integer('created_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
16
+ createdAt: integer('created_at', { mode: 'timestamp' })
17
+ .notNull()
18
+ .$defaultFn(() => new Date()),
15
19
  updatedAt: integer('updated_at', { mode: 'timestamp' }),
16
20
  })
17
21
  ```
18
22
 
19
23
  ## Tipos de Colunas
20
24
 
21
- | Tipo | Uso | Exemplo |
22
- | --- | --- | --- |
23
- | `text()` | Strings, UUIDs, JSON | `text('name').notNull()` |
24
- | `integer()` | Números, booleans, timestamps | `integer('age')` |
25
- | `real()` | Decimais (float) | `real('price')` |
26
- | `blob()` | Dados binários | `blob('avatar')` |
27
- | `numeric()` | Valores numéricos precisos | `numeric('amount')` |
25
+ | Tipo | Uso | Exemplo |
26
+ | ----------- | ----------------------------- | ------------------------ |
27
+ | `text()` | Strings, UUIDs, JSON | `text('name').notNull()` |
28
+ | `integer()` | Números, booleans, timestamps | `integer('age')` |
29
+ | `real()` | Decimais (float) | `real('price')` |
30
+ | `blob()` | Dados binários | `blob('avatar')` |
31
+ | `numeric()` | Valores numéricos precisos | `numeric('amount')` |
28
32
 
29
33
  ### Modes do `integer()`
30
34
 
31
35
  ```javascript
32
- integer('count') // número
33
- integer('active', { mode: 'boolean' }) // boolean (0/1)
34
- integer('created_at', { mode: 'timestamp' }) // Date (segundos)
36
+ integer('count') // número
37
+ integer('active', { mode: 'boolean' }) // boolean (0/1)
38
+ integer('created_at', { mode: 'timestamp' }) // Date (segundos)
35
39
  integer('created_at', { mode: 'timestamp_ms' }) // Date (milissegundos)
36
40
  ```
37
41
 
38
42
  ### JSON via `text()`
39
43
 
40
44
  ```javascript
41
- text('metadata', { mode: 'json' }) // armazena JSON como text
45
+ text('metadata', { mode: 'json' }) // armazena JSON como text
42
46
  ```
43
47
 
44
48
  ## Primary Key
@@ -55,11 +59,17 @@ id: integer('id').primaryKey({ autoIncrement: true }),
55
59
 
56
60
  ```javascript
57
61
  export const posts = sqliteTable('posts', {
58
- id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
59
- authorId: text('author_id').notNull().references(() => users.id),
62
+ id: text('id')
63
+ .primaryKey()
64
+ .$defaultFn(() => crypto.randomUUID()),
65
+ authorId: text('author_id')
66
+ .notNull()
67
+ .references(() => users.id),
60
68
  title: text('title').notNull(),
61
69
  body: text('body'),
62
- createdAt: integer('created_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
70
+ createdAt: integer('created_at', { mode: 'timestamp' })
71
+ .notNull()
72
+ .$defaultFn(() => new Date()),
63
73
  })
64
74
  ```
65
75
 
@@ -84,8 +94,12 @@ export const postsRelations = relations(posts, ({ one }) => ({
84
94
 
85
95
  ```javascript
86
96
  export const usersToGroups = sqliteTable('users_to_groups', {
87
- userId: text('user_id').notNull().references(() => users.id),
88
- groupId: text('group_id').notNull().references(() => groups.id),
97
+ userId: text('user_id')
98
+ .notNull()
99
+ .references(() => users.id),
100
+ groupId: text('group_id')
101
+ .notNull()
102
+ .references(() => groups.id),
89
103
  })
90
104
 
91
105
  export const usersRelations = relations(users, ({ many }) => ({
@@ -22,21 +22,21 @@ const app = new Elysia()
22
22
  .post('/users', ({ body }) => createUser(body), {
23
23
  body: t.Object({
24
24
  name: t.String(),
25
- email: t.String({ format: 'email' })
26
- })
25
+ email: t.String({ format: 'email' }),
26
+ }),
27
27
  })
28
28
  .listen(3000)
29
29
  ```
30
30
 
31
31
  ## Content Map
32
32
 
33
- | File | Description | When to Read |
34
- | --- | --- | --- |
35
- | [elysia-basics.md](references/elysia-basics.md) | Setup, routes, handlers, context | Starting new project |
36
- | [elysia-plugins.md](references/elysia-plugins.md) | Plugins, guards, modular design | Organizing code |
37
- | [elysia-validation.md](references/elysia-validation.md) | TypeBox validation (body, query, params) | Input validation |
38
- | [elysia-lifecycle.md](references/elysia-lifecycle.md) | Hooks (onBeforeHandle, onError, etc.) | Middleware, auth checks |
39
- | [elysia-patterns.md](references/elysia-patterns.md) | REST patterns, responses, pagination | API design |
33
+ | File | Description | When to Read |
34
+ | ------------------------------------------------------- | ---------------------------------------- | ----------------------- |
35
+ | [elysia-basics.md](references/elysia-basics.md) | Setup, routes, handlers, context | Starting new project |
36
+ | [elysia-plugins.md](references/elysia-plugins.md) | Plugins, guards, modular design | Organizing code |
37
+ | [elysia-validation.md](references/elysia-validation.md) | TypeBox validation (body, query, params) | Input validation |
38
+ | [elysia-lifecycle.md](references/elysia-lifecycle.md) | Hooks (onBeforeHandle, onError, etc.) | Middleware, auth checks |
39
+ | [elysia-patterns.md](references/elysia-patterns.md) | REST patterns, responses, pagination | API design |
40
40
 
41
41
  ## Project Structure
42
42
 
@@ -61,13 +61,13 @@ src/
61
61
 
62
62
  ## Dependencies
63
63
 
64
- | Pacote | Versão | Descrição |
65
- |---|---|---|
66
- | `bun` | latest | Runtime |
67
- | `elysia` | latest | Framework HTTP |
68
- | `bun:sqlite` | builtin | SQLite driver |
69
- | `drizzle-orm` | latest | ORM |
70
- | `bun:s3` | latest | S3/R2 Storage |
64
+ | Pacote | Versão | Descrição |
65
+ | ------------- | ------- | -------------- |
66
+ | `bun` | latest | Runtime |
67
+ | `elysia` | latest | Framework HTTP |
68
+ | `bun:sqlite` | builtin | SQLite driver |
69
+ | `drizzle-orm` | latest | ORM |
70
+ | `bun:s3` | latest | S3/R2 Storage |
71
71
 
72
72
  ## Core Patterns
73
73
 
@@ -84,8 +84,8 @@ export const userRoutes = new Elysia({ prefix: '/users' })
84
84
  .post('/', ({ body }) => createUser(body), {
85
85
  body: t.Object({
86
86
  name: t.String({ minLength: 1 }),
87
- email: t.String({ format: 'email' })
88
- })
87
+ email: t.String({ format: 'email' }),
88
+ }),
89
89
  })
90
90
  ```
91
91
 
@@ -112,11 +112,11 @@ console.log(`Server running at ${app.server?.url}`)
112
112
 
113
113
  ## Related Skills
114
114
 
115
- | Need | Skill |
116
- | --- | --- |
115
+ | Need | Skill |
116
+ | ------------------ | ---------------------------------------- |
117
117
  | **Authentication** | @[.agent/skills/riligar-dev-auth-elysia] |
118
- | **Database** | @[.agent/skills/riligar-dev-database] |
119
- | **Infrastructure** | @[.agent/skills/riligar-infra-fly] |
118
+ | **database** | @[.agent/skills/riligar-dev-database] |
119
+ | **Infrastructure** | @[.agent/skills/riligar-infra-fly] |
120
120
 
121
121
  ## Decision Checklist
122
122
 
@@ -126,14 +126,14 @@ Before building an API:
126
126
  - [ ] Planned validation for all inputs?
127
127
  - [ ] Error handling configured?
128
128
  - [ ] Auth middleware needed? → Use `riligar-dev-auth-elysia`
129
- - [ ] Database connection setup? → Use `riligar-dev-database`
129
+ - [ ] database connection setup? → Use `riligar-dev-database`
130
130
 
131
131
  ## Anti-Patterns
132
132
 
133
- | Don't | Do |
134
- | --- | --- |
135
- | Put business logic in handlers | Extract to `services/` |
136
- | Skip input validation | Use TypeBox (`t.Object`) |
137
- | Ignore error handling | Use `onError` lifecycle |
138
- | Create monolithic files | Split into plugins |
133
+ | Don't | Do |
134
+ | -------------------------------- | ------------------------ |
135
+ | Put business logic in handlers | Extract to `services/` |
136
+ | Skip input validation | Use TypeBox (`t.Object`) |
137
+ | Ignore error handling | Use `onError` lifecycle |
138
+ | Create monolithic files | Split into plugins |
139
139
  | Use verbs in routes (`/getUser`) | Use nouns (`/users/:id`) |
@@ -21,8 +21,9 @@ Pergunte ao usuário:
21
21
  > Você pode encontrá-las em: https://dashboard.stripe.com/apikeys
22
22
  >
23
23
  > Por favor, me forneça:
24
- > 1. **Publishable Key** (pk_live_... ou pk_test_...)
25
- > 2. **Secret Key** (sk_live_... ou sk_test_...)
24
+ >
25
+ > 1. **Publishable Key** (pk*live*... ou pk*test*...)
26
+ > 2. **Secret Key** (sk*live*... ou sk*test*...)
26
27
 
27
28
  Aguarde as chaves antes de prosseguir.
28
29
 
@@ -36,6 +37,7 @@ Após receber as chaves, pergunte:
36
37
  > 2. **Quais planos/produtos** você quer oferecer?
37
38
  >
38
39
  > Exemplo de resposta:
40
+ >
39
41
  > - Assinatura mensal
40
42
  > - Plano Starter: R$ 29/mês (5 projetos, suporte email)
41
43
  > - Plano Pro: R$ 99/mês (ilimitado, suporte prioritário)
@@ -57,17 +59,17 @@ async function setupProducts() {
57
59
  {
58
60
  name: 'Plano Starter',
59
61
  description: '5 projetos, suporte email',
60
- price: 2900, // R$ 29,00 em centavos
62
+ price: 2900, // R$ 29,00 em centavos
61
63
  interval: 'month',
62
- features: ['5 projetos', 'Suporte email', '1GB storage']
64
+ features: ['5 projetos', 'Suporte email', '1GB storage'],
63
65
  },
64
66
  {
65
67
  name: 'Plano Pro',
66
68
  description: 'Ilimitado, suporte prioritário',
67
- price: 9900, // R$ 99,00 em centavos
69
+ price: 9900, // R$ 99,00 em centavos
68
70
  interval: 'month',
69
- features: ['Projetos ilimitados', 'Suporte prioritário', '10GB storage']
70
- }
71
+ features: ['Projetos ilimitados', 'Suporte prioritário', '10GB storage'],
72
+ },
71
73
  ]
72
74
 
73
75
  console.log('Criando produtos no Stripe...\n')
@@ -76,14 +78,14 @@ async function setupProducts() {
76
78
  const stripeProduct = await stripe.products.create({
77
79
  name: product.name,
78
80
  description: product.description,
79
- metadata: { features: JSON.stringify(product.features) }
81
+ metadata: { features: JSON.stringify(product.features) },
80
82
  })
81
83
 
82
84
  const stripePrice = await stripe.prices.create({
83
85
  product: stripeProduct.id,
84
86
  unit_amount: product.price,
85
87
  currency: 'brl',
86
- recurring: product.interval ? { interval: product.interval } : undefined
88
+ recurring: product.interval ? { interval: product.interval } : undefined,
87
89
  })
88
90
 
89
91
  console.log(`✓ ${product.name}`)
@@ -111,6 +113,7 @@ Após executar o script, peça:
111
113
  Com as chaves e Price IDs, configure os arquivos de ambiente:
112
114
 
113
115
  **Backend: `.env.development` e `.env.production`**
116
+
114
117
  ```bash
115
118
  # .env.development (chaves de teste)
116
119
  STRIPE_SECRET_KEY=sk_test_...
@@ -122,6 +125,7 @@ STRIPE_WEBHOOK_SECRET=whsec_...
122
125
  ```
123
126
 
124
127
  **Frontend: `.env.development` e `.env.production`**
128
+
125
129
  ```bash
126
130
  # .env.development
127
131
  VITE_STRIPE_PUBLISHABLE_KEY=pk_test_...
@@ -130,7 +134,7 @@ VITE_STRIPE_PUBLISHABLE_KEY=pk_test_...
130
134
  VITE_STRIPE_PUBLISHABLE_KEY=pk_live_...
131
135
  ```
132
136
 
133
- ### Step 6: Configurar Database
137
+ ### Step 6: Configurar database
134
138
 
135
139
  Gere a migration para adicionar campos do Stripe:
136
140
 
@@ -153,29 +157,29 @@ Instrua o usuário:
153
157
  > 2. Clique em "Add endpoint"
154
158
  > 3. URL: `https://seu-dominio.com/api/webhook`
155
159
  > 4. Selecione os eventos:
156
- > - `checkout.session.completed`
157
- > - `customer.subscription.updated`
158
- > - `customer.subscription.deleted`
159
- > - `invoice.paid`
160
- > - `invoice.payment_failed`
161
- > 5. Copie o "Signing secret" (whsec_...)
160
+ > - `checkout.session.completed`
161
+ > - `customer.subscription.updated`
162
+ > - `customer.subscription.deleted`
163
+ > - `invoice.paid`
164
+ > - `invoice.payment_failed`
165
+ > 5. Copie o "Signing secret" (whsec\_...)
162
166
  > 6. Adicione ao `.env.development` e `.env.production`
163
167
 
164
168
  ### Step 8: Gerar Código
165
169
 
166
170
  Gere todos os arquivos necessários usando os templates de [assets/](assets/):
167
171
 
168
- | Arquivo | Baseado em |
169
- | --- | --- |
170
- | `plugins/stripe.js` | stripe-server.js (seção 1) |
171
- | `routes/billing.js` | stripe-server.js (seção 2) |
172
- | `routes/webhook.js` | stripe-server.js (seção 3) |
173
- | `services/billing.js` | stripe-server.js (seção 4) |
174
- | `config/stripe-prices.js` | Price IDs coletados (Step 9) |
175
- | `config/plans.js` | PLAN_MAP + PLAN_LIMITS (Step 9) |
176
- | `pages/Pricing.jsx` | stripe-client.js (seção 3) |
177
- | `components/BillingSettings.jsx` | stripe-client.js (seção 4) |
178
- | `hooks/useSubscription.js` | stripe-client.js (seção 2) |
172
+ | Arquivo | Baseado em |
173
+ | -------------------------------- | ------------------------------- |
174
+ | `plugins/stripe.js` | stripe-server.js (seção 1) |
175
+ | `routes/billing.js` | stripe-server.js (seção 2) |
176
+ | `routes/webhook.js` | stripe-server.js (seção 3) |
177
+ | `services/billing.js` | stripe-server.js (seção 4) |
178
+ | `config/stripe-prices.js` | Price IDs coletados (Step 9) |
179
+ | `config/plans.js` | PLAN_MAP + PLAN_LIMITS (Step 9) |
180
+ | `pages/Pricing.jsx` | stripe-client.js (seção 3) |
181
+ | `components/BillingSettings.jsx` | stripe-client.js (seção 4) |
182
+ | `hooks/useSubscription.js` | stripe-client.js (seção 2) |
179
183
 
180
184
  ### Step 9: Criar Configs de Planos e Preços
181
185
 
@@ -188,24 +192,24 @@ export const STRIPE_PRICES = {
188
192
  priceId: 'price_COLETADO_STARTER',
189
193
  name: 'Starter',
190
194
  price: 29,
191
- features: ['5 projetos', 'Suporte email', '1GB storage']
195
+ features: ['5 projetos', 'Suporte email', '1GB storage'],
192
196
  },
193
197
  pro: {
194
198
  priceId: 'price_COLETADO_PRO',
195
199
  name: 'Pro',
196
200
  price: 99,
197
- features: ['Projetos ilimitados', 'Suporte prioritário', '10GB storage']
201
+ features: ['Projetos ilimitados', 'Suporte prioritário', '10GB storage'],
198
202
  },
199
203
  enterprise: {
200
204
  priceId: 'price_COLETADO_ENTERPRISE',
201
205
  name: 'Enterprise',
202
206
  price: 299,
203
- features: ['Tudo do Pro', 'Storage ilimitado', 'SLA garantido']
204
- }
207
+ features: ['Tudo do Pro', 'Storage ilimitado', 'SLA garantido'],
208
+ },
205
209
  }
206
210
 
207
- export const getPrice = (plan) => STRIPE_PRICES[plan]
208
- export const getPriceId = (plan) => STRIPE_PRICES[plan]?.priceId
211
+ export const getPrice = plan => STRIPE_PRICES[plan]
212
+ export const getPriceId = plan => STRIPE_PRICES[plan]?.priceId
209
213
  ```
210
214
 
211
215
  **B) Arquivo de mapeamento e limites (config/plans.js):**
@@ -215,9 +219,9 @@ export const getPriceId = (plan) => STRIPE_PRICES[plan]?.priceId
215
219
 
216
220
  // Mapeia Price IDs do Stripe para nomes de planos internos
217
221
  export const PLAN_MAP = {
218
- 'price_COLETADO_STARTER': 'starter',
219
- 'price_COLETADO_PRO': 'pro',
220
- 'price_COLETADO_ENTERPRISE': 'enterprise',
222
+ price_COLETADO_STARTER: 'starter',
223
+ price_COLETADO_PRO: 'pro',
224
+ price_COLETADO_ENTERPRISE: 'enterprise',
221
225
  }
222
226
 
223
227
  // Define limites de features por plano
@@ -283,12 +287,12 @@ stripe trigger checkout.session.completed
283
287
 
284
288
  ## Specialized Guides
285
289
 
286
- | Guide | Content |
287
- | --- | --- |
288
- | [stripe-elysia.md](references/stripe-elysia.md) | Backend routes completas |
289
- | [stripe-react.md](references/stripe-react.md) | Componentes React/Mantine |
290
- | [stripe-webhooks.md](references/stripe-webhooks.md) | Handlers de eventos |
291
- | [stripe-database.md](references/stripe-database.md) | Schema Drizzle |
290
+ | Guide | Content |
291
+ | --------------------------------------------------- | ------------------------- |
292
+ | [stripe-elysia.md](references/stripe-elysia.md) | Backend routes completas |
293
+ | [stripe-react.md](references/stripe-react.md) | Componentes React/Mantine |
294
+ | [stripe-webhooks.md](references/stripe-webhooks.md) | Handlers de eventos |
295
+ | [stripe-database.md](references/stripe-database.md) | Schema Drizzle |
292
296
 
293
297
  ---
294
298