diff --git a/CLAUDE.md b/CLAUDE.md index 2a58e931..b7d53f52 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,8 +10,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co - Backend: FastAPI + Python for Arduino code compilation via arduino-cli - Simulation: Real AVR8 emulation using avr8js with full GPIO/timer/USART support - Components: Visual electronic components from wokwi-elements (LEDs, resistors, buttons, etc.) -- Auth: Email/password + Google OAuth, JWT in httpOnly cookies -- Project persistence: SQLite via SQLAlchemy 2.0 async + aiosqlite +- Auth: None — OSS is single-user anonymous. Accounts + OAuth live in the + velxio-prod private overlay that powers velxio.dev. +- Project persistence: `.vlx` file export/import (`utils/vlxFile.ts`) — + zero server-side state. Server-side persistence (SQLite or Postgres + via SQLAlchemy) lives in the velxio-prod overlay. The project uses **local clones of official Wokwi repositories** in `third-party/` instead of npm packages. @@ -167,8 +170,8 @@ The simulation runs at ~60 FPS using `requestAnimationFrame`: Main stores: - `useEditorStore`: Multi-file workspace (files[], activeFileId, openFileIds) - `useSimulatorStore`: Simulation state, components, wires, compiled hex, serialMonitorOpen -- `useAuthStore`: Auth state (persisted in localStorage) -- `useProjectStore`: Current project tracking +- `useProjectStore`: Current loaded project metadata (id, slug, name) — used by the `.vlx` exporter to pick a download filename +- `useAuthStore` (overlay-only) lives in `pro/frontend/src/pro/store/` in the velxio-prod repo. Pure OSS builds do not include it. **6. Component-Pin Mapping** @@ -193,25 +196,35 @@ Wire positions auto-update when components move via `updateWirePositions()`. ## Key File Locations -### Backend -- [backend/app/main.py](backend/app/main.py) - FastAPI app entry point, CORS config, model imports -- [backend/app/api/routes/compile.py](backend/app/api/routes/compile.py) - Compilation endpoints (multi-file) -- [backend/app/api/routes/auth.py](backend/app/api/routes/auth.py) - /api/auth/* endpoints -- [backend/app/api/routes/projects.py](backend/app/api/routes/projects.py) - /api/projects/* + /api/user/* +### Backend (OSS — stateless) +- [backend/app/main.py](backend/app/main.py) - FastAPI app entry point, CORS, lifespan hooks +- [backend/app/api/routes/compile.py](backend/app/api/routes/compile.py) - Compilation endpoints (multi-file, sync + async) +- [backend/app/api/routes/compile_chip.py](backend/app/api/routes/compile_chip.py) - Custom-chip WASM compile +- [backend/app/api/routes/libraries.py](backend/app/api/routes/libraries.py) - arduino-cli library search/install proxy +- [backend/app/api/routes/simulation.py](backend/app/api/routes/simulation.py) - WebSocket bridge to QEMU workers +- [backend/app/api/routes/iot_gateway.py](backend/app/api/routes/iot_gateway.py) - HTTP proxy for ESP32 web servers - [backend/app/services/arduino_cli.py](backend/app/services/arduino_cli.py) - arduino-cli wrapper -- [backend/app/core/config.py](backend/app/core/config.py) - Settings (SECRET_KEY, DATABASE_URL `velxio.db`, GOOGLE_*) -- [backend/app/core/security.py](backend/app/core/security.py) - JWT, password hashing -- [backend/app/core/dependencies.py](backend/app/core/dependencies.py) - get_current_user, require_auth -- [backend/app/database/session.py](backend/app/database/session.py) - async SQLAlchemy engine -- [backend/app/models/user.py](backend/app/models/user.py) - User model -- [backend/app/models/project.py](backend/app/models/project.py) - Project model (UniqueConstraint user_id+slug) +- [backend/app/services/espidf_compiler.py](backend/app/services/espidf_compiler.py) - ESP-IDF compile wrapper +- [backend/app/core/config.py](backend/app/core/config.py) - Minimal Settings (FRONTEND_URL only) +- [backend/app/core/hooks.py](backend/app/core/hooks.py) - Extension hooks (record_compile, get_current_user_id, lifespan_startup) that the velxio-prod overlay fills in. OSS-default = no-op. + +**Removed in the OSS/pro split (Phase 1-4):** auth.py, projects.py, +admin.py, metrics.py, models/*, schemas/*, services/metrics.py, +services/odoo_mail.py, services/project_files.py, database/session.py, +core/dependencies.py, core/security.py, utils/{geo,slug,boards}.py. All +of these live in [velxio-prod](https://github.com/velxio/velxio-prod)'s +private overlay and are COPYed onto the image at Docker build time when +deploying velxio.dev. ### Frontend - Core -- [frontend/src/App.tsx](frontend/src/App.tsx) - Main app component, routing +- [frontend/src/App.tsx](frontend/src/App.tsx) - Main app component, routing (with overlay route injection via `useProRoutes`) +- [frontend/src/lib/proRoutes.ts](frontend/src/lib/proRoutes.ts) - Registry for routes the overlay registers at runtime +- [frontend/src/lib/proSession.ts](frontend/src/lib/proSession.ts) - Optional session-check hook installed by the overlay +- [frontend/src/lib/proSaveAction.ts](frontend/src/lib/proSaveAction.ts) - Save-button registry. Default = download `.vlx`; overlay overrides with SaveProjectModal. +- [frontend/src/utils/vlxFile.ts](frontend/src/utils/vlxFile.ts) - Portable project export/import (no server needed) - [frontend/src/store/useEditorStore.ts](frontend/src/store/useEditorStore.ts) - Multi-file workspace state - [frontend/src/store/useSimulatorStore.ts](frontend/src/store/useSimulatorStore.ts) - Simulation state, components, wires -- [frontend/src/store/useAuthStore.ts](frontend/src/store/useAuthStore.ts) - Auth state (localStorage) -- [frontend/src/store/useProjectStore.ts](frontend/src/store/useProjectStore.ts) - Current project +- [frontend/src/store/useProjectStore.ts](frontend/src/store/useProjectStore.ts) - Current loaded project metadata ### Frontend - Editor UI - [frontend/src/components/editor/CodeEditor.tsx](frontend/src/components/editor/CodeEditor.tsx) - Monaco editor (key={activeFileId} for per-file undo history) @@ -409,9 +422,6 @@ metadata staleness check), not the other two. ### 9. Backend Gotchas -- **bcrypt**: Pin `bcrypt==4.0.1` — bcrypt 5.x breaks passlib 1.7.4 -- **email-validator**: Must be installed separately (`pip install email-validator`) -- **Model imports**: Both `app.models.user` and `app.models.project` must be imported before DB init (done in `main.py`) - **RP2040 board manager**: arduino-cli needs the earlephilhower URL before `rp2040:rp2040` install: ``` arduino-cli config add board_manager.additional_urls \ @@ -486,11 +496,10 @@ Enable verbose logging: - ILI9341 TFT display simulation - Library Manager (install/search arduino libraries) - Example projects gallery -- **Auth**: email/password + Google OAuth, JWT httpOnly cookies -- **Project persistence**: create/read/update/delete with URL slugs (`/:username/:slug`) -- **User profile page** at `/:username` +- **Portable project persistence**: `.vlx` file export/import — single-file JSON snapshot of the whole workspace, no server, no DB - **Resizable file explorer** panel (drag handle, collapse toggle) - Docker standalone image published to GHCR + Docker Hub +- **OSS / pro split**: auth, accounts, public profiles, admin panel, server-side project URLs and analytics live in the private [velxio-prod](https://github.com/velxio/velxio-prod) overlay that runs velxio.dev. OSS is single-user, anonymous, fully self-hostable. **In Progress:** - Functional wire connections (electrical signal routing) diff --git a/README.md b/README.md index 5842080f..770800b6 100644 --- a/README.md +++ b/README.md @@ -237,13 +237,19 @@ See [docs/RASPBERRYPI3_EMULATION.md](docs/RASPBERRYPI3_EMULATION.md) for full te - Browse and install the full Arduino library index directly from the UI - Live search, installed tab, version display -### Auth & Project Persistence +### Portable Project Persistence -- **Email/password** and **Google OAuth** sign-in -- **Project save** with name, description, and public/private visibility -- **Project URL** — each project gets a permanent URL at `/project/:id` -- **Sketch files stored on disk** per project (accessible from the host via Docker volume) -- **User profile** at `/:username` showing public projects +- **`.vlx` file format** — single-file JSON snapshot of the whole + workspace (boards, file groups, components, wires). Download with the + Save button, restore with the Open `.vlx` button. The format is + versioned so files round-trip cleanly across versions. +- **Zero server-side state** — OSS Velxio has no database, no accounts, + no login. Your projects live wherever you keep your `.vlx` files + (local disk, Dropbox, GitHub, Google Drive — your choice). +- Need accounts, public profiles at `/:username`, server-side project + URLs and admin panels? Those live in the private overlay used to run + velxio.dev — see [velxio-prod](https://github.com/velxio/velxio-prod) + for the open-core split details. ### Example Projects @@ -329,20 +335,13 @@ required** to get going. #### Optional: customize environment -Create `backend/.env` (copy from `backend/.env.example`) only when you need -OAuth, a fixed `SECRET_KEY`, or HTTPS-only cookies. The compose file picks -it up automatically if it exists. +The OSS image has almost no configuration — there's no database, no auth, +no third-party integrations. Create `backend/.env` only if you want to +change the CORS origin used during local development. | Variable | Default | Description | | --- | --- | --- | -| `SECRET_KEY` | *(auto-generated)* | JWT signing secret. If unset the entrypoint creates one and saves it under `data/.secret_key`. | -| `DATABASE_URL` | `sqlite+aiosqlite:////app/data/velxio.db` | SQLite path | -| `DATA_DIR` | `/app/data` | Directory for project files | -| `FRONTEND_URL` | `http://localhost:5173` | Used for OAuth redirect | -| `GOOGLE_CLIENT_ID` | — | Google OAuth client ID | -| `GOOGLE_CLIENT_SECRET` | — | Google OAuth client secret | -| `GOOGLE_REDIRECT_URI` | `http://localhost:8001/api/auth/google/callback` | Must match Google Console | -| `COOKIE_SECURE` | `false` | Set `true` when serving over HTTPS | +| `FRONTEND_URL` | `http://localhost:5173` | Origin allowed by CORS for local Vite dev | > **Deploying behind a reverse proxy?** The container listens on plain HTTP > on port 80 and accepts any `Host` header — no `server_name` whitelist. @@ -451,16 +450,16 @@ velxio/ | Layer | Stack | | --- | --- | | Frontend | React 19, Vite 7, TypeScript 5.9, Monaco Editor, Zustand, React Router 7 | -| Backend | FastAPI, SQLAlchemy 2.0 async, aiosqlite, uvicorn | +| Backend | FastAPI, uvicorn (stateless: compile, libraries, simulation, MCP) | | AVR Simulation | avr8js (ATmega328p / ATmega2560) | | RP2040 Simulation | rp2040js (ARM Cortex-M0+) | | RISC-V Simulation | RiscVCore.ts (RV32IMC, custom TypeScript) | | ESP32 Simulation | QEMU 8.1.3 lcgamboa fork (Xtensa LX6/LX7) | | Raspberry Pi 3 Simulation | QEMU 8.1.3 (`qemu-system-aarch64 -M raspi3b`) + Raspberry Pi OS Trixie | | UI Components | wokwi-elements (Web Components) | -| Compiler | arduino-cli (subprocess) | -| Auth | JWT (httpOnly cookie), Google OAuth 2.0 | -| Persistence | SQLite + disk volume (`/app/data/projects/{id}/`) | +| Compiler | arduino-cli (subprocess) + ESP-IDF (subprocess) | +| Auth | None — anonymous, single-user editor by design | +| Persistence | `.vlx` file export/import (no server-side database) | | Deploy | Docker, nginx, GitHub Actions → GHCR + Docker Hub | --- diff --git a/backend/.env.example b/backend/.env.example index e89f6002..a5fbcf9e 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -1,26 +1,10 @@ -# Velxio backend environment variables -# Copy this file to backend/.env and edit as needed. +# Velxio OSS backend environment variables. +# The OSS image has no auth, no database, no third-party integrations — +# this file is almost empty for a reason. Copy to backend/.env only if +# you actually need to change a setting. -# JWT signing secret — REQUIRED. Use a long random string in production. -SECRET_KEY=change-me-in-production-use-a-long-random-string - -# SQLite database path (async driver). -# Docker default points at the /app/data volume. -DATABASE_URL=sqlite+aiosqlite:////app/data/velxio.db - -# Directory where per-project sketch files are stored. -DATA_DIR=/app/data - -# Frontend URL — used for OAuth redirects and CORS. +# CORS origin allowed during local Vite development. The Docker image +# accepts any Host header, so this only matters when running the +# backend on its own (uvicorn) and the frontend on a separate dev +# server. Production deployments use a host nginx reverse proxy instead. FRONTEND_URL=http://localhost:5173 - -# Google OAuth credentials (leave empty to disable Google login). -GOOGLE_CLIENT_ID= -GOOGLE_CLIENT_SECRET= -GOOGLE_REDIRECT_URI=http://localhost:8001/api/auth/google/callback - -# Set to true when serving over HTTPS (controls Secure flag on JWT cookie). -COOKIE_SECURE=false - -# JWT access token lifetime in minutes (default: 7 days). -ACCESS_TOKEN_EXPIRE_MINUTES=10080 diff --git a/backend/app/core/config.py b/backend/app/core/config.py index 3a85ab7a..14337853 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -2,39 +2,23 @@ from pydantic_settings import BaseSettings class Settings(BaseSettings): - SECRET_KEY: str = "change-me-in-production-use-a-long-random-string" - DATABASE_URL: str = "sqlite+aiosqlite:///./velxio.db" - DATA_DIR: str = "." - GOOGLE_CLIENT_ID: str = "" - GOOGLE_CLIENT_SECRET: str = "" - GOOGLE_REDIRECT_URI: str = "http://localhost:8001/api/auth/google/callback" + """OSS settings — stateless deployment. + + Auth, DB, OAuth, billing, mail relay etc. moved to the velxio-prod + private overlay during the Phase 1-4 OSS/pro split. The overlay + physically replaces this file at Docker build time with a richer + Settings class that ADDS those fields on top of FRONTEND_URL (see + pro/backend/app/core/config.py). + + Adding a setting here means the stateless OSS image will read it. + If the new setting only makes sense with an auth/DB stack (e.g. + SMTP creds, third-party API keys for analytics), add it to the + overlay's config.py instead so the OSS image stays minimal. + """ + + # CORS — used by main.py to whitelist the SPA origin during local dev + # and to build redirect URLs from auth routes in the overlay. FRONTEND_URL: str = "http://localhost:5173" - # Set to true in production (HTTPS). Controls the Secure flag on the JWT cookie. - COOKIE_SECURE: bool = False - ACCESS_TOKEN_EXPIRE_MINUTES: int = 10080 # 7 days - - # ── Odoo transactional-mail relay ────────────────────────────────────── - # The Velxio backend POSTs to `/velxio/api/send-welcome` and - # `/velxio/api/send-password-reset` on register / forgot- - # password. Calls are fire-and-forget — registration succeeds even when - # ODOO_URL is empty (no mail will be sent), so dev / CI doesn't need a - # working Odoo instance. - # - # ODOO_API_KEY must match the company-level X-Velxio-API-Key stored in - # `res.company.velxio_api_key` on the Odoo side (see - # odoo-addons/velxio_subscription/controllers/api.py). - ODOO_URL: str = "" - ODOO_API_KEY: str = "" - # How long to wait for Odoo before giving up the fire-and-forget call. - # Kept short so a stalled Odoo never holds an asyncio.create_task open - # for minutes. - ODOO_MAIL_TIMEOUT_S: float = 10.0 - - # Password-reset tuning. Tokens are random 32-byte URL-safe strings; - # only the SHA-256 hash is persisted so a database leak doesn't reveal - # usable reset codes. - PASSWORD_RESET_TOKEN_TTL_MINUTES: int = 60 - PASSWORD_RESET_RATE_LIMIT_PER_HOUR: int = 3 model_config = {"env_file": ".env", "env_file_encoding": "utf-8"} diff --git a/backend/requirements.txt b/backend/requirements.txt index 5d9f6873..391b76f5 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,21 +1,14 @@ +# Velxio OSS backend — stateless: compile, libraries, simulation, +# iot_gateway, MCP. No auth, no DB, no project persistence; those live in +# the velxio-prod private overlay's pro/backend/requirements.txt and are +# pip-installed on top of this list at Docker build time. fastapi==0.115.0 uvicorn[standard]==0.32.0 websockets>=12.0 -sqlalchemy==2.0.36 -# greenlet is needed by SQLAlchemy async on some Python builds (notably Windows -# Python 3.12+ wheels). Without it, app startup fails with -# "ValueError: the greenlet library is required". See issue #120. -greenlet>=3.0.0 -aiosqlite==0.20.0 pydantic>=2.11.0 pydantic-settings>=2.6.0 -python-multipart==0.0.12 -python-jose[cryptography]==3.3.0 -passlib[bcrypt]==1.7.4 -bcrypt==4.0.1 +# httpx — iot_gateway proxy + MCP httpx>=0.27.1 -authlib==1.3.1 -email-validator==2.2.0 mcp>=1.0.0 esptool>=4.7.0 # WASM runtime for Custom Chips on ESP32 (chip's WASM runs in the QEMU worker diff --git a/docs/ESP32_EMULATION.md b/docs/ESP32_EMULATION.md index 0ab15d4b..507200af 100644 --- a/docs/ESP32_EMULATION.md +++ b/docs/ESP32_EMULATION.md @@ -251,11 +251,10 @@ docker run -d \ --name velxio \ -p 3080:80 \ -v $(pwd)/data:/app/data \ - -e SECRET_KEY=your-secret \ ghcr.io/davidmonterocrespo24/velxio:master ``` -ESP32 emulation with full GPIO is active automatically. No additional environment variables are needed. +ESP32 emulation with full GPIO is active automatically. No environment variables are needed (the OSS image is stateless — no auth, no DB). ### 2.2 Local Image Build @@ -263,7 +262,7 @@ ESP32 emulation with full GPIO is active automatically. No additional environmen git clone https://github.com/davidmonterocrespo24/velxio.git cd velxio docker build -f Dockerfile.standalone -t velxio . -docker run -d -p 3080:80 -e SECRET_KEY=secret velxio +docker run -d -p 3080:80 velxio ``` > **Build time note:** QEMU compilation takes 15-30 minutes the first time. @@ -1108,7 +1107,7 @@ The connection logic lives in `SimulatorCanvas.tsx`: it detects the tag of the w ```bash # Docker — fully automatic, no extra variables needed: -docker run -d -p 3080:80 -e SECRET_KEY=secret ghcr.io/davidmonterocrespo24/velxio:master +docker run -d -p 3080:80 ghcr.io/davidmonterocrespo24/velxio:master # Windows with lib (full emulation: GPIO + WiFi + ADC + I2C + SPI + RMT + LEDC): cd backend && venv\Scripts\activate