Files
indie/PLAN.md
2026-07-02 01:15:16 +05:45

19 KiB
Raw Blame History

Indie — Independent Website Platform

A platform that lets anyone create, own, and publish their own static website through AI prompts. No drag-and-drop builder — just describe what you want, and the AI generates it. Every site is backed by a git repository. Users self-host or use free subdomain hosting.


Tech Stack

Layer Technology
Backend Java 17, Spring Boot 3.x, Gradle (Groovy)
Frontend Angular 17, Angular Material
Relational DB PostgreSQL
Document DB MongoDB (generation versions, LLM sessions)
Object Storage Cloudflare R2 (S3-compatible)
LLM Gemini (primary), OpenAI (fallback), provider-abstraction for future
Auth Spring Security + OAuth2 Client — email/password, Google OAuth, GitHub OAuth, OpenID Connect
Git JGit — local repo per site, optional GitHub/GitLab remote push
Infra Docker Compose (dev), R2 + Cloudflare (hosting), nginx (prod reverse proxy)

Core Interaction Model

Prompt + Reference URLs
       │
       ▼
  ┌──────────────────┐     ┌─────────────────┐
  │  LLM generates   │────▶│  Version saved   │
  │  site structure   │     │  to timeline     │
  └──────────────────┘     └─────────────────┘
       │                           │
       ▼                           ▼
  ┌──────────────────────────────────────────┐
  │    Workspace Layout:                     │
  │  ┌──────────┬──────────────────────────┐ │
  │  │ Version  │   Live Preview           │ │
  │  │ Timeline │   (sandboxed iframe)     │ │
  │  │ sidebar  │                          │ │
  │  └──────────┴──────────────────────────┘ │
  │  ┌──────────────────────────────────────┐ │
  │  │ Content Editor (grouped by page)     │ │
  │  │ ▼ Homepage                           │ │
  │  │   Heading: [editable text]           │ │
  │  │   Body:    [editable text]           │ │
  │  │ ▼ About (collapsible)               │ │
  │  └──────────────────────────────────────┘ │
  └──────────────────────────────────────────┘
       │
       ▼
  Refine via new prompt or inline text edits
       │
       ▼
  Publish → Export → Git → Hosting

Build Phases

v0.1 — Auth & Foundation (Target: Weeks 1-3)

Goal: User can register, log in via email or OAuth, and create/manage sites.

Backend

File Action Details
backend/build.gradle Add Spring Boot 3.x, deps: web, jpa, security, oauth2-client, oauth2-resource-server, validation, lombok, postgresql, testcontainers, aws-java-sdk-s3 (R2), springdoc-openapi, jgit
backend/settings.gradle Add Project name, plugin management
backend/src/main/resources/application.yml Add DB configs, JWT keys, OAuth client IDs/secrets, LLM keys, R2 credentials, git config
com/indie/IndieApplication.java Add Main class
com/indie/config/SecurityConfig.java Add SecurityFilterChain with JWT filter + OAuth2 login + OpenID Connect. Route permissions: /api/auth/** public, /api/** authenticated
com/indie/config/JwtConfig.java Add RS256 signing, access token 15min, refresh token 7d
com/indie/config/GitConfig.java Add Repos root path (/var/git/sites/), author name/email
com/indie/model/User.java Add id(UUID), email, password(bcrypt, nullable), name, avatarUrl, provider(LOCAL/GOOGLE/GITHUB/OPENID), providerId, emailVerified, createdAt, updatedAt
com/indie/model/Site.java Add id, userId, name, description, subdomain(unique), status(DRAFT/PUBLISHED), publishedAt, createdAt, updatedAt
com/indie/repository/*.java Add JPA repositories for User, Site
com/indie/service/AuthService.java Add register, login, refreshToken, oauthLogin
com/indie/service/OAuth2UserService.java Add Maps Google/GitHub/OpenID user info to User entity
com/indie/controller/AuthController.java Add POST /api/auth/register, /login, /refresh, /logout
com/indie/controller/SiteController.java Add Full CRUD: GET/POST /api/sites, GET/PUT/DELETE /api/sites/{id}

Frontend

File Action Details
frontend/ Init Angular 17 standalone, Angular Material, lazy routes, Tailwind CSS
src/app/auth/ Add LoginComponent, RegisterComponent, OAuth callback handler, AuthService, AuthGuard, JWT interceptor
src/app/dashboard/ Add DashboardComponent (list site cards), CreateSiteDialog, DeleteSiteDialog

Infrastructure

File Action Details
docker-compose.yml Add PostgreSQL, MongoDB, MinIO (local R2 mock), backend (8080), frontend (4200)

v0.2 — LLM Prompt Workspace (Target: Weeks 4-7)

Goal: User opens a site, types a prompt describing their desired website, optionally adds reference URLs, and the AI generates it. User can refine via follow-up prompts or edit text inline. Each generation is saved as a version in a timeline.

Backend

File Action Details
com/indie/service/llm/LLMProvider.java Add Interface: generate(systemPrompt, userPrompt, references, options) → LLMResult
com/indie/service/llm/GeminiProvider.java Add Primary provider. Supports multimodal (text + images via URL)
com/indie/service/llm/OpenAIProvider.java Add Secondary/fallback
com/indie/service/llm/LLMFactory.java Add Provider routing + fallback chain
com/indie/dto/SiteStructure.java Add Top-level DTO: List<PageStructure> pages, SiteTheme theme. Each PageStructure: id, title, slug, List<ComponentStructure>. Each ComponentStructure: id, type, config (Map), styles (Map)
com/indie/dto/Reference.java Add type(URL/IMAGE), url, altText
com/indie/model/GenerationVersion.java Add MongoDB: sessionId, versionNumber, prompt, references(List), full SiteStructure(JSON), createdAt. Linked to a site
com/indie/service/LLMService.java Add Orchestrator: validate prompt → build system prompt with references → call LLM → parse → validate schema → store version → return SiteStructure
com/indie/service/LLMResponseParser.java Add Parse LLM JSON output, handle markdown fences, malformed fields, partial extraction, default values
com/indie/controller/LLMController.java Add POST /api/llm/generate (prompt + references → SiteStructure), POST /api/llm/refine (existing structure + new prompt → updated structure), GET /api/llm/versions/{siteId} (timeline list), POST /api/llm/versions/{id}/restore
com/indie/service/ReferenceService.java Add For URL references: fetch page content/extract info for LLM context. Upload button present for future use; for MVP, URL-only
com/indie/config/RateLimitConfig.java Add Rate limiting: 10 generations/hour/user
src/main/resources/prompts/site-generator.txt Add System prompt: schema definition + 2-3 few-shot examples (blog, portfolio, landing page)

Frontend

File Action Details
src/app/workspace/workspace.component.ts Add Main workspace layout: prompt area (top), preview (center-right), version timeline (right sidebar), content editor (bottom panel)
src/app/workspace/prompt-input/ Add PromptInputComponent — expanding textarea, reference URL chip input, Upload button (file picker, MVP: URL only). Generate + Refine buttons
src/app/workspace/preview/ Add PreviewComponent — sandboxed iframe rendering generated HTML (srcdoc). Device toggle (desktop 1200px, tablet 768px, mobile 375px). Styled to feel like a browser window
src/app/workspace/version-timeline/ Add VersionTimelineComponent — Material vertical stepper list. Each entry: version number, short prompt summary (truncated), timestamp, thumbnail. Current version highlighted. Click to preview that version. Restore button with confirmation dialog
src/app/workspace/content-editor/ Add ContentEditorComponent — expandable Material accordion grouped by page. Each page section contains editable fields for each text component (heading text, body text, button labels, image alt texts, etc.). Style edits (colors, fonts) go through prompts. Changes update preview in real time
src/app/workspace/services/llm-session.service.ts Add Manages: activeVersion, version list, current prompt, references
src/app/workspace/services/workspace-state.service.ts Add BehaviorSubject store: currentStructure$, versions$, selectedVersion$, draftEdits$, previewHtml$
src/app/workspace/services/preview-renderer.service.ts Add Takes SiteStructure + any draft edits → generates HTML string for iframe srcdoc

Component types for generated sites:

  • heading — text, level (h1-h6)
  • text — rich text (HTML, sanitized on output)
  • image — src, alt, caption
  • button — label, url, style
  • divider — style, color
  • gallery — image list, layout
  • video — embed URL
  • contact_form — fields config
  • map — address, zoom
  • custom_html — raw HTML

Version storage: Each generation attempt creates a MongoDB document (GenerationVersion) with the full site structure. Timeline fetched sorted by versionNumber desc. Max 100 versions per site.


v0.3 — Export, Git & Hosting (Target: Weeks 8-11)

Goal: User can publish their site as pure static files. Every publish creates a git commit. User can connect GitHub/GitLab for automatic pushes. Sites served at *.indie.com for free.

Backend

File Action Details
com/indie/service/RenderService.java Add Core render engine: renderSite(structure) → SiteOutput. Takes SiteStructure → generates HTML, CSS, JS strings. Uses Thymeleaf templates per component type
com/indie/engine/templates/*.html Add Thymeleaf templates per component + layout.html (page shell) + head.html (SEO meta)
com/indie/engine/StyleCompiler.java Add Theme → CSS custom properties at :root, component styles → CSS classes, responsive breakpoints
com/indie/engine/JsBundle.java Add Generates script.js: nav toggle, smooth scroll, lightbox, contact form handler, comment form handler. Minified
com/indie/service/ExportService.java Add export(siteId) → ZipOutputStream — full site directory + .git/
com/indie/controller/ExportController.java Add GET /api/sites/{id}/exportapplication/zip download
com/indie/service/GitService.java Add initRepo(siteId), commit(siteId, message), commitAndPush(siteId, message), getLog(siteId), rollback(siteId, commitHash), exportRepo(siteId)
com/indie/model/GitRemote.java Add JPA: id, siteId, provider(GITHUB/GITLAB), remoteUrl, encryptedToken, defaultBranch
com/indie/service/KeyManager.java Add SSH keypair generation per site, encrypted storage
com/indie/controller/GitController.java Add POST /api/sites/{id}/git/connect, /disconnect, GET /api/sites/{id}/git/status
com/indie/service/DeploymentService.java Add On publish: render → write to git working dir → GitService.commit → upload to R2 → return public URL
com/indie/controller/DeploymentController.java Add POST /api/sites/{id}/publish, /unpublish
com/indie/service/DomainService.java Add Skeleton: store custom domain mapping in Site entity, prepared for future TLS
com/indie/service/MediaService.java Add Upload to R2, validate type/size, resize. Upload button present but MVP is URL-only
com/indie/controller/MediaController.java Add POST /api/media/upload, GET /api/media/{id}

Frontend

File Action Details
src/app/workspace/git-settings/ Add GitSettingsComponent — connect/disconnect GitHub/GitLab OAuth, select remote repo, connection status indicator
src/app/workspace/settings/ Add SettingsComponent — site name, subdomain, export zip button, publish/unpublish buttons

Infrastructure

File Action Details
infra/cloudflare-worker.js Add Routes *.indie.com → R2 bucket indie-sites/{subdomain}/
docker-compose.prod.yml Add Production services: PostgreSQL, MongoDB, backend (×2), nginx, certbot

Git directory structure on server:

/var/git/sites/
  └── {siteId}/
      ├── .git/
      ├── index.html
      ├── about/index.html
      ├── style.css
      ├── script.js
      └── assets/

Output file structure (zip export):

site-export/
├── index.html
├── about/index.html
├── contact/index.html
├── style.css
├── script.js
├── assets/images/
│   ├── hero.jpg
│   └── gallery-1.jpg
├── 404.html
└── .git/

v0.4 — Social Features & Polish (Target: Weeks 12-13)

Goal: Minimal social features (comments, RSS) and final polish before public release.

Backend

File Action Details
com/indie/model/Comment.java Add JPA: id(UUID), siteId, pageId, authorName, authorEmail, content, isApproved, parentCommentId, createdAt
com/indie/controller/CommentController.java Add Public: POST /api/sites/{subdomain}/comments. Authenticated: GET/PUT/DELETE moderation
com/indie/service/RssService.java Add generateRss(siteId) → String — RSS 2.0 feed from site pages
com/indie/controller/RssController.java Add GET /api/feed/{subdomain}application/rss+xml, 1h cache

Frontend

File Action Details
src/app/workspace/settings/ Modify Add git history panel (commit list, rollback button, download repo button)
src/app/workspace/components/comments-section/ Add In-workspace config (enable/disable, moderate) + renderer for generated sites

Infrastructure Architecture

                    ┌──────────────────────┐
                    │    Cloudflare CDN     │
                    │ *.indie.com → R2     │
                    └────────┬─────────────┘
                             │
                    ┌────────▼─────────────┐
                    │   Cloudflare R2       │
                    │ indie-sites bucket    │
                    │ /{subdomain}/*        │
                    └──────────────────────┘
                             ▲
                    ┌────────┴─────────────┐
                    │   Spring Boot API    │
                    │   (VPS / Docker)     │
                    └────────┬─────────────┘
                             │
              ┌──────────────┼──────────────┐
              │              │              │
     ┌────────▼───┐  ┌──────▼──────┐  ┌───▼────────┐
     │ PostgreSQL  │  │   MongoDB   │  │  Git Repos  │
     │ (users,     │  │ (versions,  │  │ /var/git/   │
     │  sites)     │  │  sessions)  │  └────────────┘
     └─────────────┘  └─────────────┘

LLM Provider Abstraction

public interface LLMProvider {
    LLMResult generate(String systemPrompt, String userPrompt,
                       List<Reference> references, LLMOptions options);
    String getName();
}
# application.yml
indie:
  llm:
    active-provider: gemini
    fallback-provider: openai
    providers:
      gemini:
        api-key: ${GEMINI_API_KEY}
        model: gemini-2.0-flash
      openai:
        api-key: ${OPENAI_API_KEY}
        model: gpt-4o-mini

Adding a new provider = implement LLMProvider interface + add config block.


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. Content editor — Text edits happen in a structured form grouped by page, not inside the iframe. Style/structure changes go through prompts.

  6. No billing in MVP — Subdomain hosting is free. Monetization is post-MVP.


Validation Strategy

Release What to Test
v0.1 Register, login (email + OAuth), refresh token, site CRUD, 401 on unauthenticated
v0.2 Prompt → valid SiteStructure generated, preview renders correctly, version timeline shows history, restore works, content editor updates preview, refinement prompt modifies existing structure, reference URLs included in generation
v0.3 Exported zip opens in browser identically to preview, git init + commit works, git push to remote works, R2 upload succeeds, subdomain serves content
v0.4 Comment submit → approve → display, RSS validates, rollback restores previous version

Risk Register

Risk Likelihood Mitigation
LLM output quality inconsistent (most critical risk) High Invest heavily in system prompt + few-shot examples; solid response parser with fallbacks; allow manual text edits as safety net
Scope creep High Strict feature freeze per v0.x; ship as-is
LLM API costs Low Gemini-2.0-flash is free-tier friendly; rate limit 10/hour/user
Solo developer burnout Medium Realistic timeline; 4 releases instead of 5 saves ~2 weeks