Skip to content

Commit 62a7f23

Browse files
committed
feat: email, invites, and oauth
1 parent 1d9264e commit 62a7f23

File tree

67 files changed

+12005
-3562
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+12005
-3562
lines changed

.env.local.example

Lines changed: 91 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,104 @@
1-
# App
2-
SECRET_KEY='secret-key'
1+
# App Configuration
2+
SECRET_KEY='your-secret-key-here'
33
LITESTAR_DEBUG=true
44
LITESTAR_HOST=0.0.0.0
5-
LITESTAR_PORT=8089
6-
APP_URL=http://localhost:${LITESTAR_PORT}
5+
LITESTAR_PORT=8000
6+
APP_URL=http://localhost:8000
7+
LOG_LEVEL=20
78

8-
LOG_LEVEL=10
9-
# Database
10-
DATABASE_ECHO=true
11-
DATABASE_ECHO_POOL=true
9+
# Database Configuration
10+
DATABASE_ECHO=false
11+
DATABASE_ECHO_POOL=false
1212
DATABASE_POOL_DISABLE=false
13-
DATABASE_POOL_MAX_OVERFLOW=5
13+
DATABASE_POOL_MAX_OVERFLOW=10
1414
DATABASE_POOL_SIZE=5
1515
DATABASE_POOL_TIMEOUT=30
16-
DATABASE_URL=postgresql+psycopg://app:app@localhost:15432/app
16+
DATABASE_USER=app
17+
DATABASE_PASSWORD=app
18+
DATABASE_HOST=localhost
19+
DATABASE_PORT=5432
20+
DATABASE_DB=app
21+
DATABASE_URL=postgresql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_DB}
1722

18-
REDIS_URL=redis://localhost:16379/0
23+
# Redis Configuration
24+
REDIS_URL=redis://localhost:6379/0
1925

20-
# Worker
21-
SAQ_USE_SERVER_LIFESPAN=True
26+
# Worker Configuration
27+
SAQ_USE_SERVER_LIFESPAN=False
2228
SAQ_WEB_ENABLED=True
2329
SAQ_BACKGROUND_WORKERS=1
2430
SAQ_CONCURRENCY=1
2531

32+
# Frontend Configuration
2633
VITE_HOST=localhost
27-
VITE_PORT=5174
28-
VITE_HOT_RELOAD=True
29-
VITE_DEV_MODE=True
34+
VITE_PORT=3006
35+
ALLOWED_CORS_ORIGINS=["localhost:3006","localhost:8080","localhost:8000"]
36+
37+
# Storage Configuration
38+
APP_SCRATCH_PATH=/tmp/app
39+
40+
# Email Configuration (SMTP)
41+
EMAIL_ENABLED=true # Set to true to enable email sending
42+
EMAIL_SMTP_HOST=localhost # For MailHog: localhost, for production: your SMTP host
43+
EMAIL_SMTP_PORT=1025 # For MailHog: 1025, for production: 587 (TLS) or 465 (SSL)
44+
EMAIL_SMTP_USER= # MailHog doesn't require auth, leave empty for dev
45+
EMAIL_SMTP_PASSWORD= # MailHog doesn't require auth, leave empty for dev
46+
EMAIL_USE_TLS=false # MailHog doesn't use TLS, set true for production
47+
EMAIL_USE_SSL=false # MailHog doesn't use SSL, set true for production
48+
EMAIL_FROM_ADDRESS=noreply@localhost # Default from email
49+
EMAIL_FROM_NAME="Litestar Dev App" # Default from name
50+
EMAIL_TIMEOUT=30 # SMTP connection timeout in seconds
51+
52+
# OAuth Configuration
53+
54+
# Keycloak (Local Development OAuth Server)
55+
# ==========================================
56+
# Access Keycloak admin at: http://localhost:18080 (admin/admin)
57+
# Create a client with these settings for development OAuth testing
58+
OAUTH_ENABLED=true
59+
GOOGLE_CLIENT_ID=litestar-app # Your Keycloak client ID
60+
GOOGLE_CLIENT_SECRET=your-client-secret # Generated in Keycloak client settings
61+
GOOGLE_REDIRECT_URI=http://localhost:3000/auth/google/callback
62+
63+
# Production Google OAuth (replace Keycloak values above when deploying)
64+
# GOOGLE_CLIENT_ID=your-production-google-client-id
65+
# GOOGLE_CLIENT_SECRET=your-production-google-client-secret
66+
# GOOGLE_REDIRECT_URI=https://yourdomain.com/auth/google/callback
67+
68+
# MailHog (Development Email Testing)
69+
# ====================================
70+
# Access MailHog web UI at: http://localhost:8025
71+
# MailHog SMTP server runs on: localhost:1025
72+
# MailHog catches all emails sent to it during development
73+
74+
# Example Production Email Provider Configurations:
75+
# =================================================
76+
77+
# Gmail (requires app password):
78+
# EMAIL_SMTP_HOST=smtp.gmail.com
79+
# EMAIL_SMTP_PORT=587
80+
81+
# EMAIL_SMTP_PASSWORD=your-app-password
82+
# EMAIL_USE_TLS=true
83+
# EMAIL_USE_SSL=false
84+
85+
# SendGrid:
86+
# EMAIL_SMTP_HOST=smtp.sendgrid.net
87+
# EMAIL_SMTP_PORT=587
88+
# EMAIL_SMTP_USER=apikey
89+
# EMAIL_SMTP_PASSWORD=your-sendgrid-api-key
90+
# EMAIL_USE_TLS=true
91+
92+
# AWS SES:
93+
# EMAIL_SMTP_HOST=email-smtp.us-east-1.amazonaws.com
94+
# EMAIL_SMTP_PORT=587
95+
# EMAIL_SMTP_USER=your-ses-smtp-username
96+
# EMAIL_SMTP_PASSWORD=your-ses-smtp-password
97+
# EMAIL_USE_TLS=true
98+
99+
# Mailgun:
100+
# EMAIL_SMTP_HOST=smtp.mailgun.org
101+
# EMAIL_SMTP_PORT=587
102+
103+
# EMAIL_SMTP_PASSWORD=your-mailgun-password
104+
# EMAIL_USE_TLS=true

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ repos:
2424
- id: mixed-line-ending
2525
- id: trailing-whitespace
2626
- repo: https://github.com/charliermarsh/ruff-pre-commit
27-
rev: "v0.11.12"
27+
rev: "v0.11.13"
2828
hooks:
2929
# Run the linter.
3030
- id: ruff

CLAUDE.md

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ This file provides essential guidance for Claude Code when working with the Lite
77
```bash
88
# Setup
99
make install # Fresh installation
10-
cp .env.local.example .env # Setup environment
11-
make start-infra # Start PostgreSQL + Redis
10+
cp .env.local.example .env # Setup environment
11+
make start-infra # Start PostgreSQL + Redis + MailHog + Keycloak
12+
make keycloak-setup # Configure Keycloak OAuth client
1213
uv run app run # Start all services
14+
make mailhog # Open MailHog web UI (email testing)
15+
make keycloak # Open Keycloak admin (OAuth testing)
1316

1417
# Development
1518
make types # Generate TypeScript types (ALWAYS after schema changes!)
@@ -70,13 +73,13 @@ from app.db import models as m
7073

7174
class UserService(service.SQLAlchemyAsyncRepositoryService[m.User]):
7275
"""Service for user operations."""
73-
76+
7477
class Repo(repository.SQLAlchemyAsyncRepository[m.User]):
7578
"""User repository."""
7679
model_type = m.User
77-
80+
7881
repository_type = Repo
79-
82+
8083
# Custom service methods here
8184
```
8285

@@ -141,10 +144,32 @@ make test-all
141144
- `make test`
142145
- `make check-all`
143146

147+
## 📧 Email Development with MailHog
148+
149+
MailHog is configured for development email testing:
150+
151+
- **Web UI**: <http://localhost:18025> (view all emails)
152+
- **SMTP Server**: localhost:11025 (app sends emails here)
153+
- **Access**: `make mailhog` to open web interface
154+
- **Configuration**: Already set in `.env.local.example`
155+
156+
All emails sent during development are caught by MailHog instead of being delivered.
157+
158+
## 🔐 OAuth Development with Keycloak
159+
160+
Keycloak provides a local OAuth server for development:
161+
162+
- **Admin Console**: <http://localhost:18080> (admin/admin)
163+
- **Auto Setup**: `make keycloak-setup` to configure OAuth client
164+
- **Access**: `make keycloak` to open admin interface
165+
- **Test User**: testuser / testpass123 (created automatically)
166+
- **Configuration**: Client credentials provided by setup script
167+
144168
## 📊 Current Work Context
145169

146170
- Email verification: ✅ Implemented
147-
- Password reset: ✅ Implemented
171+
- Password reset: ✅ Implemented
172+
- Email service: ✅ SMTP with MailHog for dev
148173
- 2FA/TOTP: ✅ Implemented (configurable)
149174
- OAuth: Backend ✅ | Frontend ❌ | Tests ❌
150175
- Production validation: Backend 70% ✅ | Frontend ❌ | Tests ❌

Makefile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,37 @@ infra-logs: ## Tail development infras
215215
@echo "${INFO} Tailing infrastructure logs... 📋"
216216
@docker compose -f tools/deploy/docker/docker-compose.infra.yml logs -f
217217

218+
.PHONY: mailhog
219+
mailhog: ## Open MailHog web interface
220+
@echo "${INFO} Opening MailHog web interface... 📧"
221+
@echo "${INFO} MailHog UI: http://localhost:18025"
222+
@echo "${INFO} SMTP Server: localhost:11025"
223+
@if command -v open >/dev/null 2>&1; then \
224+
open http://localhost:18025; \
225+
elif command -v xdg-open >/dev/null 2>&1; then \
226+
xdg-open http://localhost:18025; \
227+
else \
228+
echo "${WARN} Please open http://localhost:18025 in your browser"; \
229+
fi
230+
231+
.PHONY: keycloak
232+
keycloak: ## Open Keycloak admin console
233+
@echo "${INFO} Opening Keycloak admin console... 🔐"
234+
@echo "${INFO} Keycloak Admin: http://localhost:18080"
235+
@echo "${INFO} Username: admin | Password: admin"
236+
@if command -v open >/dev/null 2>&1; then \
237+
open http://localhost:18080; \
238+
elif command -v xdg-open >/dev/null 2>&1; then \
239+
xdg-open http://localhost:18080; \
240+
else \
241+
echo "${WARN} Please open http://localhost:18080 in your browser"; \
242+
fi
243+
244+
.PHONY: keycloak-setup
245+
keycloak-setup: ## Setup Keycloak with development OAuth client
246+
@echo "${INFO} Setting up Keycloak for development... 🔧"
247+
@bash tools/deploy/docker/keycloak-setup.sh
248+
218249
.PHONY: start-all
219250
start-all: ## Start local containers
220251
@echo "${INFO} Starting local infrastructure... 🚀"

docs/architecture/01-overview.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,4 +178,4 @@ Now that you understand the high-level architecture:
178178

179179
---
180180

181-
*This overview provides the foundation for understanding the Litestar Fullstack SPA architecture. Each subsequent section will dive deeper into specific aspects of the system.*
181+
*This overview provides the foundation for understanding the Litestar Fullstack SPA architecture. Each subsequent section will dive deeper into specific aspects of the system.*

docs/architecture/02-project-structure.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ from advanced_alchemy.base import UUIDAuditBase
8686
class User(UUIDAuditBase):
8787
"""User account model."""
8888
__tablename__ = "user_account"
89-
89+
9090
email: Mapped[str] = mapped_column(String(255), unique=True)
9191
is_verified: Mapped[bool] = mapped_column(default=False)
9292
```
@@ -116,10 +116,10 @@ from litestar.plugins.sqlalchemy import service, repository
116116

117117
class UserService(service.SQLAlchemyAsyncRepositoryService[User]):
118118
"""Handles user operations."""
119-
119+
120120
class Repo(repository.SQLAlchemyAsyncRepository[User]):
121121
model_type = User
122-
122+
123123
repository_type = Repo
124124
```
125125

@@ -189,7 +189,7 @@ export function TeamList() {
189189
queryKey: ["teams"],
190190
queryFn: () => api.teams.listTeams()
191191
});
192-
192+
193193
return (
194194
<div className="grid gap-4">
195195
{teams?.map(team => (
@@ -289,7 +289,7 @@ services:
289289
POSTGRES_PASSWORD: app
290290
ports:
291291
- "5432:5432"
292-
292+
293293
redis:
294294
image: redis:7-alpine
295295
ports:
@@ -376,4 +376,4 @@ Continue to [Backend Architecture](03-backend-architecture.md) for deep dive int
376376

377377
---
378378

379-
*This structure promotes scalability, maintainability, and developer productivity. Each directory has a clear purpose, making it easy to locate and organize code.*
379+
*This structure promotes scalability, maintainability, and developer productivity. Each directory has a clear purpose, making it easy to locate and organize code.*

0 commit comments

Comments
 (0)