230 lines
8.9 KiB
Markdown
230 lines
8.9 KiB
Markdown
# 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
|