# 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. --- ## Quick Start ### Prerequisites - Java 17+ - Node.js 18+ and npm - Docker & Docker Compose (for PostgreSQL, MongoDB, MinIO) - Angular CLI 17 (`npm install -g @angular/cli@17`) - Gradle wrapper (included) ### Setup 1. **Start infrastructure:** ```bash docker compose up -d ``` 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`. ### Environment Variables | Variable | Description | Default | |----------|-------------|---------| | `SPRING_DATASOURCE_URL` | PostgreSQL JDBC URL | `jdbc:postgresql://localhost:5432/indie` | | `SPRING_DATASOURCE_USERNAME` | DB username | `indie` | | `SPRING_DATASOURCE_PASSWORD` | DB password | `indie_dev` | | `SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GOOGLE_CLIENT_ID` | Google OAuth 2.0 client ID (omit to disable Google login) | — | | `SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GOOGLE_CLIENT_SECRET` | Google OAuth 2.0 client secret | — | | `SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GITHUB_CLIENT_ID` | GitHub OAuth App client ID (omit to disable GitHub login) | — | | `SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GITHUB_CLIENT_SECRET` | GitHub OAuth App client secret | — | | `INDIE_JWT_ACCESS_EXPIRATION` | Access token TTL (ms) | `900000` (15 min) | | `INDIE_JWT_REFRESH_EXPIRATION` | Refresh token TTL (ms) | `604800000` (7 days) | | `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` | --- ## 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/indie/ │ ├── IndieApplication.java # Spring Boot main class │ ├── config/ │ │ ├── SecurityConfig.java # HTTP security, JWT filter, OAuth2 login, CORS │ │ ├── JwtConfig.java # RS256 token generation and validation │ │ └── GitConfig.java # Git repository settings │ ├── model/ │ │ ├── User.java # User entity with local + OAuth support │ │ ├── Site.java # Site entity per user │ │ ├── Page.java # Page within a site │ │ ├── Component.java # Component on a page (heading, text, image, etc.) │ │ ├── JsonbConverter.java # JPA converter for JSONB columns │ │ └── *.java # Enums (AuthProvider, SiteStatus, ComponentType) │ ├── repository/ │ │ ├── UserRepository.java │ │ ├── SiteRepository.java │ │ ├── PageRepository.java │ │ └── ComponentRepository.java │ ├── dto/ │ │ ├── RegisterRequest.java │ │ ├── LoginRequest.java │ │ ├── RefreshTokenRequest.java │ │ ├── AuthResponse.java # JWT tokens + user info │ │ ├── SiteRequest.java │ │ ├── SiteResponse.java │ │ ├── PageRequest.java │ │ └── PageResponse.java │ ├── service/ │ │ ├── AuthService.java # Register, login, token refresh │ │ ├── OAuth2UserService.java # Maps Google/GitHub user info to User entity │ │ └── OAuth2SuccessHandler.java # Redirects with JWT after OAuth login │ └── controller/ │ ├── AuthController.java # POST /api/auth/register, /login, /refresh, /logout │ ├── SiteController.java # CRUD /api/sites │ └── PageController.java # CRUD /api/sites/{siteId}/pages └── resources/ └── application.yml # All configuration frontend/ ├── proxy.conf.json # Dev proxy to backend ├── angular.json # Angular CLI configuration ├── tailwind.config.js # Tailwind CSS configuration ├── package.json └── src/ ├── index.html ├── styles.css # Global styles + Tailwind imports └── app/ ├── app.component.ts # Root component ├── app.config.ts # App providers ├── app.routes.ts # Lazy-loaded routes ├── core/ │ ├── models/ │ │ ├── auth-response.ts # AuthResponse & UserInfo interfaces │ │ ├── site.ts # SiteResponse interface │ │ └── page.ts # PageResponse interface │ ├── services/ │ │ ├── auth.service.ts # Auth HTTP + token storage │ │ ├── site.service.ts # Site CRUD HTTP │ │ └── page.service.ts # Page CRUD HTTP │ ├── guards/ │ │ └── auth.guard.ts # Route guard (redirects to /login) │ └── interceptors/ │ └── jwt.interceptor.ts # Attaches Bearer token ├── auth/ │ ├── login/ │ │ └── login.component.ts # Email/password login form │ └── register/ │ └── register.component.ts # Name/email/password register form └── dashboard/ ├── dashboard.component.ts # Site cards grid + toolbar ├── create-site-dialog/ │ └── create-site-dialog.ts # Create site dialog └── delete-site-dialog/ └── delete-site-dialog.ts # Confirm delete dialog ``` --- ## API Overview ### Authentication (`/api/auth`) | Method | Path | Description | |--------|------|-------------| | POST | `/api/auth/register` | Register with email + password | | POST | `/api/auth/login` | Login with email + password | | POST | `/api/auth/refresh` | Refresh access token | | POST | `/api/auth/logout` | Logout | ### Sites (`/api/sites`) | Method | Path | Description | |--------|------|-------------| | GET | `/api/sites` | List user's sites | | POST | `/api/sites` | Create a new site | | GET | `/api/sites/{id}` | Get site details | | PUT | `/api/sites/{id}` | Update site | | DELETE | `/api/sites/{id}` | Delete site | ### Pages (`/api/sites/{siteId}/pages`) | Method | Path | Description | |--------|------|-------------| | GET | `/api/sites/{siteId}/pages` | List pages for a site | | POST | `/api/sites/{siteId}/pages` | Create a new page | | GET | `/api/sites/{siteId}/pages/{pageId}` | Get page details | | PUT | `/api/sites/{siteId}/pages/{pageId}` | Update page | | DELETE | `/api/sites/{siteId}/pages/{pageId}` | Delete page | --- ## Tech Stack | Layer | Technology | |-------|-----------| | Backend | Java 17, Spring Boot 3.2, Gradle | | Frontend | Angular 17, Angular Material, Tailwind CSS | | Relational DB | PostgreSQL 16 | | Document DB | MongoDB 7 | | Object Storage | MinIO (dev) / Cloudflare R2 (prod) | | Auth | Spring Security + OAuth2 Client + JWT (RS256) | | Git | JGit | | API Docs | Springdoc OpenAPI (Swagger UI) | --- ## Development ```bash # Backend cd backend ./gradlew build # Build ./gradlew test # Run tests ./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 ``` --- ## Build Status ### v0.1 — Auth & Foundation ✅ - [x] User registration (email/password) - [x] User login (email/password + JWT) - [x] OAuth2 login (Google, GitHub) with JWT redirect - [x] Token refresh with 7-day refresh token - [x] Site CRUD (create, list, get, update, delete) - [x] Page CRUD within a site - [x] Frontend: Login, Register, OAuth callback pages - [x] Frontend: Dashboard with site cards, create/delete dialogs - [x] Frontend: JWT interceptor, auth guard, lazy routes