# Vibers — Arquitetura / Architecture

> Documento vivo. Versão inicial escrita junto com a **Fase 1**.
> Living document. Initial version written alongside **Phase 1**.
>
> Idioma: o texto principal está em português; termos técnicos, nomes de classes,
> tabelas e ações ficam em inglês (são os nomes reais usados no código).
> Language: prose is in Portuguese with English summaries; class, table and action
> names are in English because they are the real identifiers in the code.

---

## 0. Resumo executivo / Executive summary

**PT** — A Vibers é um monólito PHP 8.2 modular (sem framework), com MySQL/MariaDB,
Bootstrap 5 e JavaScript vanilla. A IA **nunca executa nada**: ela devolve *ações estruturadas
em JSON*; a plataforma valida (schema → política → caminho → tamanho → extensão → projeto) e
só então executa, sempre dentro do workspace e do banco isolados do projeto. Trabalho longo
roda em uma fila baseada em tabela MySQL, consumida por um worker CLI.

**EN** — Vibers is a modular, framework-less PHP 8.2 monolith with MySQL/MariaDB,
Bootstrap 5 and vanilla JS. **AI never executes anything**: it returns *structured JSON
actions*; the platform validates them (schema → policy → path → size → extension → project)
and only then executes them, always inside the project's isolated workspace and database.
Long-running work goes through a MySQL-table job queue consumed by a CLI worker.

---

## 1. Análise da especificação / Specification analysis

| Tema / Topic | Decisão / Decision |
|---|---|
| Framework | Nenhum. Micro-núcleo próprio (`app/Core`: Router, Request, Response, View, Database, Env, Lang, Logger). ~600 linhas, fácil de auditar. / None; tiny in-house core. |
| Composer | `composer.json` existe apenas para o autoload PSR-4 futuro; **a Fase 1 não depende de `vendor/`** (autoloader próprio). SDKs de IA não são necessários — chamadas HTTP via cURL. / Only for future autoload; Phase 1 has zero dependencies. |
| Multi-tenancy | Um diretório + um banco + um usuário MySQL **por projeto**. / One dir + one DB + one DB user per project. |
| IDs | `id` interno (BIGINT) nunca aparece em URL; URLs usam `uuid` (v4). Acesso de outro usuário responde **404** (não 403) para não revelar existência. / Internal IDs never exposed; foreign access returns 404. |
| Idioma / i18n | UI bilíngue `pt-BR` (padrão) e `en`, arquivos em `lang/`. / Bilingual UI. |
| Fila / Queue | Tabela `jobs` + `bin/worker.php` (systemd/cron). `SELECT … FOR UPDATE SKIP LOCKED` não existe no MariaDB 10.4 → usamos `UPDATE … WHERE status='pending' LIMIT 1` com `locked_by` token (claim atômico). / Atomic claim via UPDATE+token. |
| Preview | Subdomínio `{uuid}.preview.dominio` → Nginx aponta para `storage/projects/{id}/public` por mapeamento gerado pela plataforma (nunca por caminho vindo do usuário). Em dev: rota `/preview/{uuid}/…` servida pelo `PreviewController`. |
| Segurança do código gerado | O código gerado roda com PHP-FPM **pool separado por projeto** (usuário Linux próprio, `open_basedir` = workspace, `disable_functions` = exec/shell_exec/system/passthru/proc_open/popen/pcntl_*). Isso é o que realmente contém código malicioso — a validação de ações é a 1ª barreira, não a única. |

**Ponto crítico / Critical point:** validar ações da IA impede que a IA escreva fora do
workspace, **mas não impede que o PHP gerado, quando executado no preview, faça algo ruim**.
Por isso o preview/produção de projetos gerados **não pode** rodar no mesmo pool PHP-FPM da
plataforma. Ver riscos R1/R2 (§8).

---

## 2. Arquitetura de diretórios / Directory layout

```
saas-factory/
├── app/
│   ├── Core/            # Router, Request, Response, View, Database, Env, Lang, Logger, ErrorHandler
│   ├── Controllers/     # finos: validam, chamam services, retornam view/JSON
│   │   └── Admin/
│   ├── Services/        # regras de negócio (AuthService, ProjectService, AuditService…)
│   ├── Repositories/    # único lugar com SQL (PDO + prepared statements)
│   ├── Models/          # objetos de dados simples (User, Project)
│   ├── Middleware/      # Auth, Guest, Csrf, Role
│   ├── Policies/        # ProjectPolicy (quem pode o quê)
│   ├── Validators/      # Validator genérico + regras
│   ├── Security/        # Csrf, SessionManager, RateLimiter, SecurityHeaders, PathGuard   (PROTEGIDO / PROTECTED)
│   ├── Support/         # Uuid, Str, helpers
│   ├── AI/              # Fase 3
│   │   ├── Core/        # AIProviderInterface, Orchestrator, PromptPolicyBuilder         (PROTEGIDO)
│   │   ├── Providers/   # OpenAIProvider, GeminiProvider, AnthropicProvider
│   │   ├── Agents/      # ProductArchitectAgent, UIUXAgent, …
│   │   └── Actions/     # ActionSchema, AIActionValidator, ActionExecutor
│   ├── Projects/        # Fase 2: ProjectBuilderService, ProjectFileService, ProjectContextBuilder, ManifestService
│   ├── Modules/         # Fase 5: ModuleCatalog, ModuleInstaller, ModuleMatcherService, DependencyResolver
│   ├── Database/        # Fase 2: DatabaseProvisioner, ProjectDatabaseService, MigrationRunner
│   ├── Deploy/          # Fase 8: DeploymentService, PreviewService
│   └── Jobs/            # Fase 3+: JobQueue, handlers
├── bin/                 # CLI: migrate.php, worker.php, create-admin.php
├── config/              # app.php, database.php, security.php, ai.php (lêem .env)            (PROTEGIDO)
├── database/
│   ├── migrations/      # SQL numerado do banco principal
│   └── seeds/
├── docs/                # este documento, decisões (ADR)
├── lang/                # pt-BR.php, en.php
├── modules/             # catálogo de módulos reutilizáveis (Fase 5)
├── templates/base-saas/ # template inicial de todo projeto (Fase 2)
├── public/              # ÚNICO diretório servido pelo webserver
│   ├── index.php
│   └── assets/{css,js,images}
├── storage/             # fora do public; gravável pelo PHP
│   ├── logs/  cache/  temp/  backups/
│   └── projects/{000001}/   # workspaces
├── tests/               # runner próprio (sem PHPUnit na Fase 1)
├── views/               # layouts/, partials/, auth/, dashboard/, projects/, settings/, admin/, errors/
├── .env.example
└── README.md
```

---

## 3. Schema inicial do banco principal / Main database schema

Banco `saasfactory_main`, `utf8mb4_unicode_ci`, InnoDB. Tabelas marcadas ✅ foram criadas na Fase 1;
as demais serão adicionadas por migrations na fase indicada.

| Tabela | Fase | Campos principais / Key columns |
|---|---|---|
| `schema_migrations` ✅ | 1 | migration, checksum (sha256), batch, executed_at |
| `users` ✅ | 1 | id, uuid, name, username, email, password_hash, role(`user/admin/superadmin`), locale, status(`active/suspended`), projects_limit, last_login_at, created_at, updated_at, deleted_at |
| `user_sessions` ✅ | 1 | id, user_id, session_hash (sha256 do id), ip, user_agent, created_at, last_seen_at, revoked_at |
| `rate_limits` ✅ | 1 | key_hash, hits, reset_at |
| `projects` ✅ | 1 | id, uuid, user_id, name, slug, description, status, build_state, current_version, database_name, project_path, preview_url, production_url, created_at, updated_at, deleted_at |
| `project_settings` ✅ | 1 | project_id, key, value |
| `project_events` ✅ | 1 | project_id, type, message, metadata(JSON), created_at |
| `audit_logs` ✅ | 1 | user_id, project_id, action, metadata(JSON), ip, user_agent, created_at |
| `project_databases` | 2 | project_id, database_name, db_username, secret_ref (credencial cifrada com sodium), status |
| `project_files` | 2 | project_id, path, sha256, size, version_id, updated_by |
| `project_versions` | 2/7 | project_id, version_number, description, created_by(`user/system/agent:<slug>`), snapshot_path, created_at |
| `project_migrations` | 2 | project_id, migration_name, checksum, status, executed_at, rollback_available |
| `project_locks` | 2 | project_id (PK), lock_token, locked_by, expires_at |
| `jobs` | 2/3 | type, payload(JSON), status, attempts, max_attempts, idempotency_key (UNIQUE), locked_by, available_at, started_at, finished_at, error |
| `ai_providers` | 3 | slug(`openai/gemini/anthropic`), enabled |
| `ai_models` | 3 | provider_id, model, input_price, output_price, context_window |
| `ai_agents` | 3 | slug, provider_model_id, temperature, enabled |
| `ai_tasks` | 3 | project_id, agent_slug, type, status, job_id |
| `ai_messages` | 3 | task_id, role, content (sem segredos), tokens |
| `ai_actions` | 4 | task_id, type, path, status(`proposed/rejected/executed/failed`), rejection_reason, payload_hash |
| `ai_usage` | 3 | provider, model, input_tokens, output_tokens, estimated_cost, project_id, user_id, task_type |
| `module_catalog` / `module_versions` / `project_modules` | 5 | slug, version, status(`development/testing/validated/deprecated`), dependencies |
| `deployments` | 8 | project_id, version_id, environment(`preview/production`), status |
| `plans` / `subscriptions` / `credits` / `credit_transactions` | 9 | saldo só muda com transação correspondente (`credit/debit/refund`) |
| `domains` / `redirects` | 10 | domain, type, status, verification_token, ssl_status / source_path, destination_url, http_code |

Decisões / Decisions:
- `projects.status` (visível ao usuário: `draft, planning, generating, testing, ready, published, error, suspended`)
  é separado de `projects.build_state` (máquina de estados interna: `idea_received → planning → architecture_ready →
  modules_selected → database_preparing → files_generating → testing → preview_ready → published`).
- Soft delete (`deleted_at`) em `users` e `projects`.
- JSON do MariaDB 10.4 é `LONGTEXT` com `CHECK(JSON_VALID())` — usado para `metadata`/`payload`.

---

## 4. Services, Controllers, Repositories

| Camada | Fase 1 (implementado) | Próximas fases |
|---|---|---|
| **Controllers** | HomeController, AuthController, DashboardController, ProjectController, SettingsController, LocaleController, Admin\AdminController | BuildController, ChatController, PreviewController, VersionController, DeployController, CreditController, DomainController, Admin\JobsController, Admin\HealthController |
| **Services** | AuthService, ProjectService, AuditService, UserService | ProjectBuilderService, ProjectFileService, ProjectDatabaseService, DatabaseProvisioner, ProjectContextBuilder, ManifestService, VersionService, ProjectLockService, ModuleMatcherService, ModuleInstaller, AIOrchestrator, AIUsageService, QAService, PhpLintService, DeploymentService, PreviewService, CreditService, BackupService (DB/Project), ServerService |
| **Repositories** | UserRepository, ProjectRepository, AuditLogRepository, SessionRepository, ProjectEventRepository | JobRepository, VersionRepository, MigrationRepository, ModuleRepository, AIUsageRepository, CreditRepository, DomainRepository |
| **Security** | Csrf, SessionManager, RateLimiter, SecurityHeaders, PathGuard (já pronto para a Fase 2) | SecretBox (libsodium), UploadGuard |
| **Middleware** | AuthMiddleware, GuestMiddleware, CsrfMiddleware, RoleMiddleware | ProjectLockMiddleware |

---

## 5. Interfaces principais / Main interfaces

```php
interface AIProviderInterface {
    public function sendMessage(AIRequest $request): AIResponse;          // JSON estrito quando pedido
    public function streamMessage(AIRequest $request, callable $onChunk): AIResponse;
    public function supportsTools(): bool;
    public function getUsage(): ?AIUsage;                                  // tokens da última chamada
    public function getModel(): string;
}

interface AgentInterface {
    public function slug(): string;                                        // 'product_architect', 'backend', …
    public function outputSchema(): array;                                 // JSON Schema da resposta
    public function allowedActions(): array;                               // subconjunto de ActionType
    public function run(AgentContext $ctx): AgentResult;
}

interface ActionHandlerInterface {                                         // um por ActionType
    public function type(): string;                                        // CREATE_FILE, RUN_MIGRATION…
    public function validate(array $action, ProjectContext $p): ValidationResult;
    public function execute(array $action, ProjectContext $p): ActionResult;
}

interface DatabaseProvisionerInterface {                                   // MySQL hoje; outro engine amanhã
    public function createDatabase(string $name): void;
    public function createUser(string $user, string $password): void;
    public function grantProjectPermissions(string $db, string $user): void; // só `db`.*
    public function dropDatabase(string $name): void;                      // exige confirmação + backup
}

interface JobQueueInterface {                                              // MySQL hoje; Redis amanhã
    public function push(string $type, array $payload, ?string $idempotencyKey = null): int;
    public function reserve(string $workerId): ?Job;
    public function complete(Job $job): void;
    public function fail(Job $job, string $error): void;
}

interface ModuleInstallerInterface {
    public function install(Project $p, string $slug): InstallResult;     // resolve dependências, idempotente
}
```

A atribuição agente → provedor/modelo fica em `config/ai.php` + tabela `ai_agents`.
**Nenhum código fora de `app/AI/Providers` cita "openai", "gemini" ou "anthropic".**

---

## 6. Fluxo de criação de projeto / Project creation flow

```
[Usuário] POST /projects (CSRF, rate limit, quota projects_limit)
   │
   ▼
ProjectService::create()         → INSERT projects (status=draft, build_state=idea_received, uuid v4)
   │                              → audit_logs 'project.create' · project_events
   ▼  (Fase 2+)
jobs: BUILD_PROJECT {project_id}  idempotency_key = "build:{id}:v1"
   │
   ▼  worker.php
ProjectLockService::acquire()
ProjectBuilderService
   1. prepareWorkspace()   storage/projects/{000127}/  (mkdir 0750, dono = usuário do pool FPM do projeto)
   2. createDatabase()     sf_project_{hex6}  + usuário sf_user_{hex6} + GRANT só nesse banco
   3. copyTemplate()       templates/base-saas → workspace (via ProjectFileService, nunca cp -r do shell)
   4. writeConfig()        workspace/config/database.php gerado pela plataforma (IA não pode editar)
   5. runMigrations()      base-saas migrations → project_migrations
   6. writeManifest()      project.json
   7. createVersion(1)     "Projeto inicial"
   8. generatePreview()    mapeamento uuid → workspace
   ▼
status=ready, build_state=preview_ready → UI faz polling de /projects/{uuid}/status
```

Cada passo grava o `build_state`; se o worker morrer, o job é re-executado e cada passo
verifica se já foi feito (**idempotência**: "banco já existe? pula").

---

## 7. Fluxo seguro de ações da IA / Secure AI action flow

```
UserRequest (texto livre, NÃO confiável)
   │
PromptPolicyBuilder
   = CoreSecurityPolicy (fixa, sempre 1ª, não removível)
   + AgentPolicy (papel + ações permitidas + JSON schema)
   + ProjectArchitecture (project.json)
   + RelevantProjectContext (ProjectContextBuilder: arquivos relevantes, schema, histórico curto)
   + UserRequest  ← delimitado como <user_request>…</user_request>, tratado como dado
   │
AIProvider (via Orchestrator) → resposta
   │
1. JSON parse estrito (texto livre → rejeitado)
2. Schema válido? (tipo de ação ∈ allowlist do agente; campos obrigatórios; sem campos extras)
3. Limites: nº de ações ≤ N, tamanho por arquivo ≤ X KB, total ≤ Y KB
4. PathGuard: relativo, sem `..`, sem `\0`, sem drive `C:`, sem absoluto, sem symlink,
   realpath(dir pai) começa com realpath(workspace), extensão na allowlist,
   não está em diretórios protegidos do projeto (config/, .env, storage/)
5. Conteúdo: varredura heurística (exec/shell_exec/system/passthru/proc_open/popen/eval/
   assert(string)/`backtick`/include de URL/base64_decode+eval/$_GET em include) → rejeita ou exige QA
6. Migration: só CREATE/ALTER/INDEX por padrão; DROP/TRUNCATE/DELETE sem WHERE → exige backup + flag
   │  qualquer falha → ai_actions.status='rejected' + security.log + NADA é executado
   ▼
ProjectLock → snapshot/versão → ActionExecutor (transação lógica: tudo ou nada)
   → PhpLintService (php -l, comando fixo, arquivo em diretório temporário)
   → QAAgent + checagens estáticas → se falhar, devolve erro ao Coding Agent (máx. 3 ciclos)
   → nova versão salva → preview atualizado
```

Ações da v1: `CREATE_FILE, UPDATE_FILE, DELETE_FILE, CREATE_DIRECTORY, READ_FILE, LIST_FILES,
RUN_MIGRATION, INSTALL_MODULE, UPDATE_MODULE, REQUEST_QA, REQUEST_PREVIEW`.
**`RUN_SHELL_COMMAND` não existe** — nem como tipo desconhecido tratado: qualquer tipo fora da lista é rejeitado.

---

## 8. Riscos técnicos / Technical risks

| # | Risco | Mitigação |
|---|---|---|
| R1 | **Código gerado malicioso/bugado executa no preview** (a IA pode escrever `exec()` sutil, ou o usuário pede "adicione um terminal web"). | Pool PHP-FPM por projeto com usuário Linux próprio, `open_basedir`, `disable_functions`, sem acesso de escrita fora de `storage/uploads`. Preview em **subdomínio separado** (cookies da plataforma não vazam). Scan de conteúdo antes de gravar. |
| R2 | Pool FPM por projeto não escala para milhares de projetos em uma VPS. | Fase inicial: pools `ondemand` (0 processos ociosos). Futuro: containers por projeto (a interface `ServerService` já isola essa decisão). |
| R3 | Credencial MySQL com `CREATE USER` / `GRANT` é poderosa. | Usuário **provisioner** separado do usuário da aplicação, usado apenas pelo worker CLI, nunca pela requisição web. Nomes de banco/usuário gerados pela plataforma (regex `^sf_(project|user)_[a-f0-9]{6,12}$`), nunca vindos da IA. |
| R4 | Prompt injection via conteúdo do projeto (ex.: arquivo contém "ignore as regras"). | Contexto do projeto também é dado não-confiável; a segurança real está no validador, não no prompt. |
| R5 | Custos de IA explodem (loops de correção). | Limite de ciclos QA↔Coder, orçamento por tarefa, `ai_usage` + débito de créditos antes/depois. |
| R6 | Concorrência (dois jobs editando o mesmo projeto). | `project_locks` com expiração + token. |
| R7 | Divergência entre arquivos em disco e `project_files`. | Toda escrita passa por `ProjectFileService`; checksum sha256 verificado. |
| R8 | Windows vs Linux (dev em XAMPP, prod em Ubuntu). | Caminhos sempre via `PathGuard`; testes rodam nos dois; provisionamento de pool FPM só existe no adapter Linux. |
| R9 | MariaDB 10.4 local sem `SKIP LOCKED`/JSON nativo. | Claim atômico por UPDATE; JSON validado por `CHECK`. Recomenda-se MariaDB ≥10.6 ou MySQL 8 em produção. |

---

## 9. Decisões em aberto / Open decisions (precisam de você / need your input)

1. **Isolamento de execução** dos SaaS gerados: pool FPM por projeto (recomendado v1) ou container por projeto desde já?
2. **Domínio** da plataforma e do preview (ex.: `saasfactory.com` + `*.preview.saasfactory.com`) — precisa de DNS wildcard + certificado wildcard (Certbot DNS-01).
3. **Provedor/modelo** por agente e orçamento máximo de tokens por projeto/plano.
4. **Git por projeto?** Versionamento v1 proposto = snapshots em `storage/backups/projects/{id}/v{n}.tar` + tabela. Git real pode entrar depois.
5. **Planos e preços** (quotas default hoje: 3 projetos por usuário, configurável em `.env`).
6. **E-mail transacional** (verificação de conta / reset de senha): SMTP de qual provedor?
7. **Login com Google** (aparece no mockup): OAuth entra em qual fase? Proposto: Fase 1.5, opcional.
8. **Termos de Uso / Política de Privacidade** — textos jurídicos (o cadastro já exige o aceite e grava `terms_accepted_at`).
9. **Idioma dos SaaS gerados**: herdam o idioma do usuário ou são sempre bilíngues?

---

## 10. Plano de implementação / Implementation plan

Cada fase = implementar → testar → corrigir → documentar → avançar.

| Fase | Entregas pequenas / Small deliverables | Status |
|---|---|---|
| **1 Fundação** | 1.1 núcleo (router, env, PDO, views, i18n, erros) · 1.2 migrations CLI · 1.3 cadastro/login/logout com CSRF, rate limit, sessão segura · 1.4 dashboard · 1.5 CRUD de projetos (uuid, soft delete, policy) · 1.6 audit log + logs separados · 1.7 área admin por role · 1.8 testes de segurança · 1.9 README | ✅ |
| **2 Workspace** | 2.1 `PathGuard`+`ProjectFileService` · 2.2 `DatabaseProvisioner` (usuário provisioner) · 2.3 `jobs` + `worker.php` · 2.4 `ProjectLockService` · 2.5 template `base-saas` · 2.6 preview em dev (`/preview/{uuid}`) · 2.7 testes de isolamento A×B | próximo |
| **3 AI Core** | interface + 3 providers (cURL) · `PromptPolicyBuilder` · Orchestrator · agentes configuráveis · `ai_usage` | |
| **4 AI Actions** | schema · `AIActionValidator` · executor · CREATE/UPDATE/READ_FILE · RUN_MIGRATION · lint | |
| **5 Módulos** | catálogo · resolver de dependências · instalador idempotente · auth, users, settings, crm | |
| **6 Fábrica** | prompt inicial → plano → matcher → pipeline → QA → tela de build (4 áreas) | |
| **7 Editor conversacional** | chat de alterações · versões · rollback | |
| **8 Deploy** | preview → produção, sem editar produção | |
| **9 Monetização** | planos · créditos transacionais · limites | |
| **10 Domínios** | domínio próprio · verificação TXT · redirects · SSL | |
