Files
indie/PLAN.md
2026-06-30 11:13:55 +05:45

17 KiB
Raw Blame History

Indie — Independent Website Platform

A platform that lets anyone create, own, and publish their own static website without social media gatekeeping. Built with a drag-and-drop builder and LLM prompt-to-site generation. 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, Angular CDK (drag-drop)
Relational DB PostgreSQL
Document DB MongoDB (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), Caddy/nginx (prod reverse proxy)

Build Phases

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

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

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), themeConfig(JSONB), status(DRAFT/PUBLISHED), publishedAt, createdAt, updatedAt
com/indie/model/Page.java Add id, siteId(FK), title, slug, seoTitle, seoDescription, orderIndex, createdAt
com/indie/model/Component.java Add id, pageId(FK), type(enum), config(JSONB), styles(JSONB), orderIndex
com/indie/repository/*.java Add JPA repositories for User, Site, Page, Component
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}
com/indie/controller/PageController.java Add CRUD for pages within a site

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 — Drag-and-Drop Builder (Target: Weeks 4-6)

Goal: User can visually build a website by dragging components onto a canvas, editing their properties, styling via theme editor, and previewing live.

Backend

File Action Details
com/indie/controller/BuilderController.java Add GET /api/sites/{id}/pages (with nested components), PUT /api/sites/{id}/pages/{pageId}/components (batch save), GET/PUT /api/sites/{id}/theme
com/indie/service/BuilderService.java Add Validate component tree (type enum, config schema, max 50/page), save in transaction

Frontend

File Action Details
src/app/builder/builder.component.ts Add 3-panel layout (palette 250px, canvas flex, properties 320px) via CSS Grid or mat-sidenav
src/app/builder/services/builder-state.service.ts Add BehaviorSubject store: components$, selectedComponentId$, themeConfig$, pages$. Methods: add, remove, update, reorder. Undo/redo stack (50 snapshots)
src/app/builder/services/auto-save.service.ts Add 2s debounce → PUT batch save. "Saving..."/"Saved" indicator
src/app/builder/component-palette/ Add PaletteComponent — Material list of 10 draggable component types, organized by category
src/app/builder/canvas/ Add CanvasComponent — cdkDropList accepting drops, renders components in order, highlight on select, delete on hover
src/app/builder/property-panel/ Add PropertyPanelComponent — dynamic form per type (config + styles sections). Material expansion panels
src/app/builder/renderer/ Add Render components per type (heading, text, image, button, divider, gallery, video, contact_form, map, custom_html) — each takes config + styles as @Input()
src/app/builder/theme-editor/ Add ThemeEditorComponent — color pickers, font selectors, spacing slider. Live preview updates
src/app/builder/preview/ Add PreviewComponent — sandboxed <iframe> with srcdoc, responsive device toggles (desktop/tablet/mobile)
src/app/builder/builder-api.service.ts Add HTTP calls for save/load components, theme, pages

Component types: heading, text, image, button, divider, gallery, video, contact_form, map, custom_html


v0.3 — LLM Prompt-to-Site (Target: Weeks 7-8)

Goal: User types a description of their desired website → AI generates the full site structure (pages + components + theme) → user tweaks in builder or refines via another prompt.

Backend

File Action Details
com/indie/service/llm/LLMProvider.java Add Interface: generate(systemPrompt, userPrompt, options) → LLMResult. LLMResult: content, tokenUsage, model, latency
com/indie/service/llm/GeminiProvider.java Add Implements LLMProvider via Gemini API. Config: indie.llm.providers.gemini.api-key, model
com/indie/service/llm/OpenAIProvider.java Add Implements LLMProvider via OpenAI API. Config: indie.llm.providers.openai.api-key, model
com/indie/service/llm/LLMFactory.java Add Returns configured provider from indie.llm.active-provider, fallback chain
com/indie/dto/LLMOptions.java Add temperature, maxTokens, timeout, responseFormat
com/indie/dto/SiteStructure.java Add Top-level DTO: List<PageStructure> pages, ThemeConfig theme. Nested types for page and component
com/indie/dto/LLMResult.java Add content(String), tokenUsage, model, latencyMs
com/indie/model/LLMSession.java Add MongoDB document: userId, prompt, generatedStructure, acceptedAt, refinedPrompt, createdAt
com/indie/service/LLMService.java Add Orchestrator: prompt → LLM → parse → validate → return SiteStructure
com/indie/service/LLMResponseParser.java Add Parse LLM JSON output, handle markdown fences, malformed fields, partial extraction
com/indie/controller/LLMController.java Add POST /api/llm/generate (prompt→structure), POST /api/llm/refine (structure+prompt→refined). Rate limit: 10/hour/user
com/indie/config/RateLimitConfig.java Add Rate limiting via bucket4j
src/main/resources/prompts/site-generator.txt Add System prompt: schema definition + 2-3 few-shot examples

Frontend

File Action Details
src/app/llm-workspace/ Add LLMWorkspaceComponent — textarea, "Generate" button, loading spinner with ETA, result preview summary, "Apply to Builder" button
src/app/llm-workspace/llm-session.service.ts Add Prompt history, refinement flow (original prompt + user edits + refinement → new generation)

v0.4 — Export, Git & Hosting (Target: Weeks 9-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(site), renderPage(site, page, components) → String, renderCss(theme, components) → String, renderJs() → String
com/indie/engine/templates/*.html Add Thymeleaf templates per component type + layout.html + head.html
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
com/indie/controller/MediaController.java Add POST /api/media/upload, GET /api/media/{id}

Frontend

File Action Details
src/app/builder/git-settings/ Add GitSettingsComponent — connect/disconnect GitHub/GitLab OAuth, select remote repo, connection status
src/app/builder/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/

v0.5 — 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/builder/settings/ Modify Add git history panel (commit list, rollback button, download repo)
src/app/builder/components/comments-section/ Add In-builder 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,     │  │ (LLM sess.) │  │ /var/git/   │
     │  sites,     │  └─────────────┘  └────────────┘
     │  pages,     │
     │  comps)     │
     └─────────────┘

LLM Provider Abstraction

// Adding a new provider = implement this interface + add config
public interface LLMProvider {
    LLMResult generate(String systemPrompt, String userPrompt, 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

Key Design Decisions

  1. Static output only — Generated sites are pure HTML/CSS/JS. No Angular/React dependency for end users. They own the output forever, no lock-in.

  2. Git as source of truth — Every site is a git repository. Publish = commit. Rollback is a git checkout. Export includes full .git/ history.

  3. Shared rendering — The same component renderers drive the builder preview AND the static export. What you see is what you get.

  4. No billing in MVP — Subdomain hosting is free. No Stripe/PayPal code. Monetization (paid hosting, custom domains) is a post-MVP concern.

  5. Incremental releases — Each v0.x is independently shippable. If timeline slips, ship what's done.


Validation Strategy

Release What to Test
v0.1 Register, login (email + OAuth), refresh token, site CRUD, page CRUD, 401 on unauthenticated
v0.2 Drag → reorder → save → reload matches, theme change reflects in preview, undo/redo, all 10 component types render
v0.3 LLM generates valid SiteStructure JSON, generation loads into builder, refinement updates correctly, error handling (timeout, bad JSON)
v0.4 Exported zip opens in browser identically to preview, git init + commit works, git push to remote works, R2 upload succeeds, subdomain serves content
v0.5 Comment submit → approve → display, RSS validates, image upload + resize, rollback restores previous version

Risk Register

Risk Likelihood Mitigation
Scope creep (adding features mid-phase) High Strict feature freeze per v0.x; ship as-is
Drag-drop performance with many components Medium Cap at 50 components/page; virtual scroll if needed
LLM output quality inconsistent Medium Iterate on system prompt; template gallery fallback
Solo developer burnout Medium Realistic timeline; celebrate each release
LLM API costs Low Gemini-2.0-flash is free-tier friendly; rate limit 10/hour/user