504 lines
23 KiB
Markdown
504 lines
23 KiB
Markdown
# Indie — Independent Website Platform
|
|
|
|
A platform that lets anyone create, own, and publish their own static website through AI prompts. Describe what you want, and the AI generates it. Every site is backed by a git repository.
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
### Prerequisites
|
|
|
|
- Java 17+
|
|
- Node.js 18+ and npm
|
|
- Docker & Docker Compose (for PostgreSQL, MongoDB)
|
|
- npm packages: `@angular/cli@17` (`npm install -g @angular/cli@17`)
|
|
|
|
### Setup
|
|
|
|
1. **Start infrastructure:**
|
|
|
|
```bash
|
|
docker compose up -d
|
|
```
|
|
|
|
This starts PostgreSQL (port 5432) and MongoDB (port 27017).
|
|
|
|
2. **Start the backend:**
|
|
|
|
```bash
|
|
cd backend
|
|
./gradlew bootRun
|
|
```
|
|
|
|
The API will be available at `http://localhost:8080`.
|
|
Swagger UI at `http://localhost:8080/swagger-ui.html`.
|
|
|
|
3. **Start the frontend (separate terminal):**
|
|
|
|
```bash
|
|
cd frontend
|
|
npm install
|
|
ng serve
|
|
```
|
|
|
|
The app will be available at `http://localhost:4200`.
|
|
API calls are proxied to `http://localhost:8080`.
|
|
|
|
---
|
|
|
|
## Infrastructure (Docker Compose)
|
|
|
|
| Service | Image | Ports | Credentials | Volume |
|
|
|------------|--------------------|--------------|--------------------------------|---------------------|
|
|
| PostgreSQL | `postgres:16-alpine` | host:5432 | `indie` / `indie_dev` | `pgdata` |
|
|
| MongoDB | `mongo:7` | host:27017 | (no auth) | `mongodata` |
|
|
|
|
---
|
|
|
|
## Environment Variables
|
|
|
|
| Variable | Description | Default |
|
|
|----------|-------------|---------|
|
|
| **Database** | | |
|
|
| `SPRING_DATASOURCE_URL` | PostgreSQL JDBC URL | `jdbc:postgresql://localhost:5432/indie` |
|
|
| `SPRING_DATASOURCE_USERNAME` | DB username | `indie` |
|
|
| `SPRING_DATASOURCE_PASSWORD` | DB password | `indie_dev` |
|
|
| `MONGODB_URI` | MongoDB connection URI | `mongodb://localhost:27017/indie` |
|
|
| **JWT** | | |
|
|
| `INDIE_JWT_ACCESS_EXPIRATION` | Access token TTL (ms) | `900000` (15 min) |
|
|
| `INDIE_JWT_REFRESH_EXPIRATION` | Refresh token TTL (ms) | `604800000` (7 days) |
|
|
| `INDIE_JWT_PRIVATE_KEY_PATH` | RS256 private key path | `config/jwt-private.key` |
|
|
| `INDIE_JWT_PUBLIC_KEY_PATH` | RS256 public key path | `config/jwt-public.key` |
|
|
| **Git** | | |
|
|
| `INDIE_GIT_REPOS_PATH` | Git repositories root | `/var/git/sites/` |
|
|
| `INDIE_GIT_AUTHOR_NAME` | Default git author name | `Indie Platform` |
|
|
| `INDIE_GIT_AUTHOR_EMAIL` | Default git author email | `git@indie.local` |
|
|
| **Encryption** | | |
|
|
| `INDIE_ENCRYPTION_KEY_PATH` | AES-256-GCM master key path | `config/encryption.key` |
|
|
| **App** | | |
|
|
| `INDIE_APP_BASE_URL` | Frontend base URL (for verification emails) | `http://localhost:4200` |
|
|
| `INDIE_VERIFICATION_TOKEN_EXPIRATION` | Email verification token TTL (minutes) | `1440` (24h) |
|
|
| `INDIE_CORS_ORIGINS` | Allowed CORS origins (comma-separated) | `http://localhost:4200,http://localhost:3000` |
|
|
| **LLM** | | |
|
|
| `GEMINI_API_KEY` | Google Gemini API key | — |
|
|
| `GEMINI_MODEL` | Gemini model name | `gemini-2.0-flash` |
|
|
| `OPENAI_API_KEY` | OpenAI API key | — |
|
|
| `OPENAI_MODEL` | OpenAI model name | `gpt-4o-mini` |
|
|
| `INDIE_LLM_RATE_LIMIT` | Max LLM requests per hour per user | `10` |
|
|
| **Email (MailHog compatible)** | | |
|
|
| `EMAIL_HOST` | SMTP host | `localhost` |
|
|
| `EMAIL_PORT` | SMTP port | `1025` |
|
|
| `EMAIL_USERNAME` | SMTP username | _(empty)_ |
|
|
| `EMAIL_PASSWORD` | SMTP password | _(empty)_ |
|
|
| `EMAIL_SMTP_AUTH` | Enable SMTP auth | `true` |
|
|
| `EMAIL_SMTP_STARTTLS` | Enable STARTTLS | `true` |
|
|
|
|
---
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
backend/
|
|
├── build.gradle # Dependencies and build config
|
|
├── settings.gradle # Project name
|
|
├── gradlew / gradlew.bat # Gradle wrapper
|
|
├── gradle/wrapper/ # Wrapper JAR + properties
|
|
└── src/
|
|
├── main/java/com/krrishg/
|
|
│ ├── IndieApplication.java # Spring Boot main class (@EnableScheduling)
|
|
│ ├── config/
|
|
│ │ ├── SecurityConfig.java # HTTP security, JWT filter, CORS
|
|
│ │ ├── JwtConfig.java # RS256 token generation and validation
|
|
│ │ ├── TokenService.java # Interface for token generation/validation
|
|
│ │ ├── JwtAuthenticationToken.java # Custom AbstractAuthenticationToken
|
|
│ │ ├── UserPrincipal.java # UserDetails record
|
|
│ │ ├── GitConfig.java # Git repository settings
|
|
|
|
│ │ ├── EncryptionService.java # AES-256/GCM for LLM API key encryption
|
|
│ │ ├── RateLimitConfig.java # Bucket4j token-bucket rate limiter
|
|
│ │ ├── SchemaMigration.java # Startup DDL migrations
|
|
│ │ ├── MapToJsonConverter.java # JPA converter for JSON text columns
|
|
│ │ └── GlobalExceptionHandler.java # @ControllerAdvice error handling
|
|
│ ├── model/
|
|
│ │ ├── User.java # User entity (email, password, emailVerified)
|
|
│ │ ├── VerificationToken.java # Email verification / set-password tokens
|
|
│ │ ├── Site.java # Site entity per user
|
|
│ │ ├── SiteStatus.java # Enum: DRAFT, PUBLISHED
|
|
│ │ ├── AuthProvider.java # Enum: LOCAL only (OAuth planned)
|
|
│ │ ├── GitRemote.java # Connected git remote (GitHub/GitLab)
|
|
│ │ ├── SelfHostedConfig.java # SSH/deploy configuration per site
|
|
│ │ └── GenerationVersion.java # MongoDB: LLM generation history per site
|
|
│ ├── repository/
|
|
│ │ ├── UserRepository.java
|
|
│ │ ├── SiteRepository.java
|
|
│ │ ├── GitRemoteRepository.java
|
|
│ │ ├── SelfHostedConfigRepository.java
|
|
│ │ └── VerificationTokenRepository.java
|
|
│ ├── dto/
|
|
│ │ ├── RegisterRequest.java
|
|
│ │ ├── RegistrationResponse.java
|
|
│ │ ├── LoginRequest.java
|
|
│ │ ├── RefreshTokenRequest.java
|
|
│ │ ├── AuthResponse.java # JWT tokens + user info
|
|
│ │ ├── VerifyEmailRequest.java
|
|
│ │ ├── VerifyEmailResponse.java
|
|
│ │ ├── ResendVerificationRequest.java
|
|
│ │ ├── SetPasswordRequest.java
|
|
│ │ ├── SiteRequest.java # Includes deploymentTarget field
|
|
│ │ ├── SiteResponse.java
|
|
│ │ ├── SiteStructure.java # Top-level DTO: pages + theme
|
|
│ │ ├── Reference.java # URL/IMAGE reference for LLM context
|
|
│ │ ├── LLMOptions.java # LLM generation options
|
|
│ │ ├── LLMResult.java # LLM generation result
|
|
│ │ ├── LLMConfigRequest.java # User LLM provider config
|
|
│ │ ├── SelfHostedConfigRequest.java
|
|
│ │ └── SelfHostedConfigResponse.java
|
|
│ ├── service/
|
|
│ │ ├── AuthService.java # Register, login, token refresh, verify email
|
|
│ │ ├── EmailService.java # Verification email sender
|
|
│ │ ├── CleanupService.java # Scheduled cleanup of stale unverified accounts
|
|
│ │ ├── LLMService.java # Orchestrates LLM calls, stores/restores versions
|
|
│ │ ├── LLMResponseParser.java # Parses LLM JSON into SiteStructure
|
|
│ │ ├── ReferenceService.java # Fetches web page content for LLM context
|
|
│ │ ├── RenderService.java # Renders SiteStructure into HTML + CSS + JS
|
|
│ │ ├── DeploymentService.java # Orchestrates publish/unpublish
|
|
│ │ ├── Deployer.java # Interface for self-hosted deployment
|
|
│ │ ├── SshRsyncDeployer.java # SSH + rsync + nginx + Let's Encrypt
|
|
│ │ ├── PagesProvider.java # Interface for git provider Pages
|
|
│ │ ├── GitHubPagesProvider.java # GitHub Pages implementation
|
|
│ │ ├── GitLabPagesProvider.java # GitLab Pages implementation
|
|
│ │ ├── GitService.java # JGit: init, commit, push, log, rollback
|
|
│ │ ├── KeyManager.java # SSH key-pair generation per site
|
|
|
|
│ │ ├── ExportService.java # Exports site structure to ZIP
|
|
│ │ └── DomainService.java # Custom domain resolution skeleton
|
|
│ ├── service/llm/
|
|
│ │ ├── LLMProvider.java # Interface for LLM providers
|
|
│ │ ├── GeminiProvider.java # Google Gemini implementation
|
|
│ │ ├── OpenAIProvider.java # OpenAI implementation
|
|
│ │ └── ProviderFactory.java # Factory creating providers by name + key
|
|
│ ├── engine/
|
|
│ │ ├── JsBundle.java # Generates static JS (nav, smooth scroll, lightbox, contact form)
|
|
│ │ └── StyleCompiler.java # Generates base CSS with custom property fallbacks
|
|
│ └── controller/
|
|
│ ├── AuthController.java # POST /api/auth/*
|
|
│ ├── SiteController.java # CRUD /api/sites
|
|
│ ├── LLMController.java # POST /api/llm/generate, /refine, /versions/*
|
|
│ ├── GitController.java # POST /api/sites/{id}/git/*
|
|
│ ├── DeploymentController.java # POST /api/sites/{id}/publish, /unpublish
|
|
│ ├── ExportController.java # GET /api/sites/{id}/export
|
|
│ ├── UserSettingsController.java # GET/PUT/DELETE /api/user/llm-config
|
|
│ └── SelfHostedController.java # CRUD /api/sites/{id}/self-hosted
|
|
├── main/resources/
|
|
│ ├── application.yml # All configuration
|
|
│ └── prompts/
|
|
│ ├── site-generator.txt # LLM system prompt for site generation
|
|
│ └── site-refiner.txt # LLM system prompt for refinement
|
|
└── test/java/com/krrishg/
|
|
├── config/ # 7 config tests
|
|
├── controller/ # 9 controller tests
|
|
├── dto/ # 7 DTO tests
|
|
├── engine/ # 2 engine tests
|
|
├── model/ # 7 model tests
|
|
├── repository/ # 4 repository tests
|
|
├── service/ # 16 service tests + fakes
|
|
├── service/llm/ # 3 LLM provider tests
|
|
└── support/ # 13 test fakes, stubs, and configs
|
|
|
|
frontend/
|
|
├── Dockerfile # Multi-stage production build
|
|
├── nginx.conf # Nginx config (SPA fallback + /api/ proxy)
|
|
├── proxy.conf.json # Dev proxy to backend
|
|
├── angular.json # Angular CLI configuration
|
|
├── tailwind.config.js # Tailwind CSS configuration
|
|
├── postcss.config.js # PostCSS (tailwindcss + autoprefixer)
|
|
├── package.json
|
|
├── tsconfig.json / tsconfig.app.json / tsconfig.spec.json
|
|
├── src/
|
|
│ ├── index.html
|
|
│ ├── main.ts # Angular bootstrap
|
|
│ ├── styles.css # Global styles + Tailwind imports
|
|
│ ├── favicon.ico
|
|
│ ├── assets/
|
|
│ └── app/
|
|
│ ├── app.component.ts / .html / .css
|
|
│ ├── app.config.ts # App providers
|
|
│ ├── app.routes.ts # Lazy-loaded routes
|
|
│ ├── core/
|
|
│ │ ├── models/
|
|
│ │ │ ├── auth-response.ts # AuthResponse & UserInfo
|
|
│ │ │ ├── site.ts # SiteResponse
|
|
│ │ │ ├── page.ts # PageResponse
|
|
│ │ │ ├── llm.ts # LLM request/response types, GenerationVersion
|
|
│ │ │ └── deployment.ts # Git/self-hosted config types
|
|
│ │ ├── services/
|
|
│ │ │ ├── auth.service.ts # Auth HTTP + token storage
|
|
│ │ │ ├── site.service.ts # Site CRUD HTTP
|
|
│ │ │ ├── page.service.ts # Page CRUD HTTP
|
|
│ │ │ ├── deployment.service.ts # Export, git, publish HTTP
|
|
│ │ │ ├── llm-api.service.ts # LLM generate/refine/version HTTP
|
|
│ │ │ └── llm-config.service.ts # User LLM key storage HTTP
|
|
│ │ ├── guards/
|
|
│ │ │ ├── auth.guard.ts # Redirects unauthenticated to /login
|
|
│ │ │ └── login.guard.ts # Redirects authenticated to /dashboard
|
|
│ │ └── interceptors/
|
|
│ │ └── jwt.interceptor.ts # Attaches Bearer token
|
|
│ ├── auth/
|
|
│ │ ├── login/
|
|
│ │ │ └── login.component.ts
|
|
│ │ ├── register/
|
|
│ │ │ └── register.component.ts
|
|
│ │ └── verify-email/
|
|
│ │ └── verify-email.component.ts # Email verification + set-password
|
|
│ ├── dashboard/
|
|
│ │ ├── dashboard.component.ts # Site cards grid + toolbar
|
|
│ │ ├── create-site-dialog/
|
|
│ │ │ └── create-site-dialog.ts
|
|
│ │ └── delete-site-dialog/
|
|
│ │ └── delete-site-dialog.ts
|
|
│ └── llm-workspace/
|
|
│ ├── llm-workspace.component.ts # Main workspace (prompt, preview, timeline)
|
|
│ ├── llm-session.service.ts # LLM generation session state
|
|
│ ├── settings/
|
|
│ │ └── settings.component.ts # LLM provider key/dialog settings
|
|
│ ├── git-settings/
|
|
│ │ └── git-settings.component.ts # Git remote connection settings
|
|
│ ├── preview-dialog/
|
|
│ │ └── preview-dialog.component.ts # Preview generated site
|
|
│ └── delete-version-dialog/
|
|
│ └── delete-version-dialog.ts # Confirm delete version
|
|
|
|
config/ # Auto-generated on first boot
|
|
├── jwt-private.key # RS256 private key
|
|
├── jwt-public.key # RS256 public key
|
|
└── encryption.key # AES-256-GCM master key (base64)
|
|
```
|
|
|
|
---
|
|
|
|
## API Overview
|
|
|
|
### Authentication (`/api/auth`)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| POST | `/api/auth/register` | Register with name + email + password (returns verification pending) |
|
|
| POST | `/api/auth/login` | Login with email + password |
|
|
| POST | `/api/auth/refresh` | Refresh access token |
|
|
| POST | `/api/auth/logout` | Logout |
|
|
| POST | `/api/auth/verify-email` | Verify email via token, returns setup token |
|
|
| POST | `/api/auth/resend-verification` | Resend verification email |
|
|
| POST | `/api/auth/set-password` | Set password after email verification |
|
|
|
|
### Sites (`/api/sites`)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/sites` | List user's sites |
|
|
| POST | `/api/sites` | Create a new site (with `deploymentTarget`: `GIT_PAGES`, `SELF_HOSTED`, or `NONE`) |
|
|
| GET | `/api/sites/{id}` | Get site details |
|
|
| PUT | `/api/sites/{id}` | Update site |
|
|
| DELETE | `/api/sites/{id}` | Delete site |
|
|
|
|
### LLM Generation (`/api/llm`)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| POST | `/api/llm/generate` | Generate site from prompt (rate-limited to 10/hour/user) |
|
|
| POST | `/api/llm/refine` | Refine existing site structure with follow-up prompt |
|
|
| GET | `/api/llm/versions/{siteId}` | List generation versions for a site |
|
|
| POST | `/api/llm/versions/{id}/restore` | Restore a specific generation version |
|
|
| DELETE | `/api/llm/versions/{id}` | Delete a generation version |
|
|
|
|
### Git Remotes (`/api/sites/{id}/git`)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| POST | `/api/sites/{id}/git/connect` | Connect git remote (GitHub/GitLab) |
|
|
| POST | `/api/sites/{id}/git/disconnect` | Disconnect git remote |
|
|
| GET | `/api/sites/{id}/git/status` | Get connection status, SSH keys, commit log |
|
|
|
|
### Deployment (`/api/sites/{id}`)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| POST | `/api/sites/{id}/publish` | Publish site (git push) |
|
|
| POST | `/api/sites/{id}/unpublish` | Unpublish site |
|
|
| GET | `/api/sites/{id}/export` | Download site as `.zip` archive |
|
|
|
|
### Self-Hosted Deployment (`/api/sites/{id}/self-hosted`)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/sites/{id}/self-hosted` | Get SSH/deploy configuration |
|
|
| PUT | `/api/sites/{id}/self-hosted` | Save SSH/deploy configuration |
|
|
| DELETE | `/api/sites/{id}/self-hosted` | Remove configuration |
|
|
|
|
### User Settings (`/api/user`)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/user/llm-config` | Get saved LLM provider configs (keys redacted) |
|
|
| PUT | `/api/user/llm-config` | Save API key / base URL / model for a provider |
|
|
| DELETE | `/api/user/llm-config/{provider}` | Delete saved config for a provider |
|
|
|
|
---
|
|
|
|
## Frontend Routes
|
|
|
|
| Path | Component | Auth |
|
|
|------|-----------|------|
|
|
| `/login` | LoginComponent | Redirects to /dashboard if already logged in |
|
|
| `/register` | RegisterComponent | Redirects to /dashboard if already logged in |
|
|
| `/verify-email` | VerifyEmailComponent | Public (email verification flow) |
|
|
| `/dashboard` | DashboardComponent | Requires auth |
|
|
| `/llm/:siteId` | LlmWorkspaceComponent | Requires auth |
|
|
| `/llm/:siteId/settings` | SettingsComponent | Requires auth |
|
|
| `/llm/:siteId/git` | GitSettingsComponent | Requires auth |
|
|
|
|
---
|
|
|
|
## Tech Stack
|
|
|
|
| Layer | Technology |
|
|
|-------|-----------|
|
|
| Backend | Java 17, Spring Boot 3.2, Gradle (Groovy) |
|
|
| Frontend | Angular 17, Angular Material, Tailwind CSS, Leaflet |
|
|
| Relational DB | PostgreSQL 16 |
|
|
| Document DB | MongoDB 7 (generation versions, LLM sessions) |
|
|
|
|
| Auth | Spring Security + JWT (RS256), email/password |
|
|
| LLM | Gemini (primary), OpenAI (fallback), provider-abstraction |
|
|
| Git | JGit — local repo per site, GitHub/GitLab remote push |
|
|
| Email | Spring Boot Mail (MailHog compatible) |
|
|
| Rate Limiting | Bucket4j |
|
|
| API Docs | Springdoc OpenAPI (Swagger UI) |
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌──────────────────────┐
|
|
│ Spring Boot API │
|
|
│ (VPS / Docker) │
|
|
└────────┬─────────────┘
|
|
│
|
|
┌──────────────┼──────────────┐
|
|
│ │ │
|
|
┌────────▼───┐ ┌──────▼──────┐ ┌───▼────────┐
|
|
│ PostgreSQL │ │ MongoDB │ │ Git Repos │
|
|
│ (users, │ │ (versions, │ │ /var/git/ │
|
|
│ sites) │ │ sessions) │ └────────────┘
|
|
└─────────────┘ └─────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Development
|
|
|
|
```bash
|
|
# Backend
|
|
cd backend
|
|
./gradlew build # Build
|
|
./gradlew test # Run tests (unit + slice + integration)
|
|
./gradlew bootRun # Run locally (requires docker compose up -d first)
|
|
|
|
# Frontend
|
|
cd frontend
|
|
npm install # Install dependencies
|
|
ng serve # Dev server at localhost:4200
|
|
ng build # Production build (outputs to dist/)
|
|
ng test # Run unit tests (Jasmine + Karma)
|
|
```
|
|
|
|
### Production Build (Docker)
|
|
|
|
```bash
|
|
docker build -t indie-frontend frontend/
|
|
docker run -p 80:80 indie-frontend
|
|
```
|
|
|
|
The frontend Docker image serves the app via nginx (port 80) and proxies `/api/` requests to `http://backend:8080`.
|
|
|
|
---
|
|
|
|
## Roadmap
|
|
|
|
### v0.1 — Auth & Foundation ✅
|
|
- [x] User registration (email/password + email verification)
|
|
- [x] User login (email/password + JWT)
|
|
- [x] Token refresh with 7-day refresh token
|
|
- [x] Site CRUD (create, list, get, update, delete)
|
|
- [x] Frontend: Login, Register, Verify Email, Dashboard
|
|
- [x] Frontend: JWT interceptor, auth guard, login guard, lazy routes
|
|
- [x] Scheduled cleanup of unverified accounts
|
|
|
|
### v0.2 — LLM Prompt Workspace ✅
|
|
- [x] Prompt-to-site generation via Gemini/OpenAI
|
|
- [x] Version timeline with MongoDB storage
|
|
- [x] Live preview (sandboxed iframe)
|
|
- [x] Content editor (grouped by page)
|
|
- [x] Refine via follow-up prompts
|
|
- [x] Rate limiting (10 generations/hour/user)
|
|
- [x] Reference URL support for context
|
|
|
|
### v0.3 — Export, Git & Hosting ✅
|
|
- [x] Render engine (HTML + CSS + JS generation)
|
|
- [x] Git init, commit, push via JGit
|
|
- [x] SSH key-pair management per site
|
|
- [x] GitHub Pages / GitLab Pages providers
|
|
- [x] Export as `.zip` archive
|
|
- [x] Publish/unpublish flow
|
|
- [x] Custom domain skeleton
|
|
- [x] Self-hosted deployment (SSH + rsync + nginx)
|
|
|
|
---
|
|
|
|
## LLM Provider Abstraction
|
|
|
|
```java
|
|
public interface LLMProvider {
|
|
LLMResult generate(String systemPrompt, String userPrompt,
|
|
List<Reference> references, LLMOptions options);
|
|
String getName();
|
|
}
|
|
```
|
|
|
|
Adding a new provider = implement `LLMProvider` interface + add config block in `application.yml`.
|
|
|
|
Provider API keys can be configured globally via env vars (`GEMINI_API_KEY`, `OPENAI_API_KEY`) or per-user through the `/api/user/llm-config` endpoint (encrypted at rest via AES-256-GCM).
|
|
|
|
---
|
|
|
|
## Key Design Decisions
|
|
|
|
1. **Pure prompt-based** — No drag-and-drop builder. Every site starts from a prompt. Iteration happens through follow-up prompts and inline text edits.
|
|
|
|
2. **Static output only** — Generated sites are pure HTML/CSS/JS. No runtime framework dependency. Users own the output forever.
|
|
|
|
3. **Git as source of truth** — Every site is a git repository. Publish = commit. Rollback = checkout. Export includes full `.git/`.
|
|
|
|
4. **Version timeline** — Every generation creates a version in MongoDB. Users can browse, preview, and restore any previous version.
|
|
|
|
5. **No billing in MVP** — Monetization is post-MVP.
|
|
|
|
---
|
|
|
|
## config/ Directory
|
|
|
|
The following files live in `config/` and are auto-generated on first boot if they don't exist.
|
|
In production, generate and mount them manually:
|
|
|
|
```bash
|
|
# RS256 key pair for JWT
|
|
openssl genpkey -algorithm RSA -out config/jwt-private.key -pkeyopt rsa_keygen_bits:2048
|
|
openssl rsa -pubout -in config/jwt-private.key -out config/jwt-public.key
|
|
|
|
# AES-256-GCM master key for LLM API key encryption
|
|
openssl rand -base64 32 > config/encryption.key
|
|
```
|
|
|
|
Set the `INDIE_JWT_PRIVATE_KEY_PATH`, `INDIE_JWT_PUBLIC_KEY_PATH`, and
|
|
`INDIE_ENCRYPTION_KEY_PATH` env vars to point to these files.
|