feat: Expand fleet to 23 skills across all domains

New skills (14):
- nestjs-best-practices: 40 priority-ranked rules (kadajett)
- fastapi: Pydantic v2, async SQLAlchemy, JWT auth (jezweb)
- architecture-patterns: Clean Architecture, Hexagonal, DDD (wshobson)
- python-performance-optimization: Profiling and optimization (wshobson)
- ai-sdk: Vercel AI SDK streaming and agent patterns (vercel)
- create-agent: Modular agent architecture with OpenRouter (openrouterteam)
- proactive-agent: WAL Protocol, compaction recovery, self-improvement (halthelobster)
- brand-guidelines: Brand identity enforcement (anthropics)
- ui-animation: Motion design with accessibility (mblode)
- marketing-ideas: 139 ideas across 14 categories (coreyhaines31)
- pricing-strategy: SaaS pricing and tier design (coreyhaines31)
- programmatic-seo: SEO at scale with playbooks (coreyhaines31)
- competitor-alternatives: Comparison page architecture (coreyhaines31)
- referral-program: Referral and affiliate programs (coreyhaines31)

README reorganized by domain: Code Quality, Frontend, Backend,
Auth, AI/Agent Building, Marketing, Design, Meta.

Mosaic Stack is not limited to coding — the Orchestrator serves
coding, business, design, marketing, writing, logistics, and analysis.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-16 16:22:53 -06:00
parent f6bcc86881
commit 861b28b965
85 changed files with 20895 additions and 25 deletions

View File

@@ -0,0 +1,64 @@
"""Authentication dependencies for route protection."""
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from src.auth import models, service
from src.database import get_db
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login")
async def get_current_user(
token: str = Depends(oauth2_scheme),
db: AsyncSession = Depends(get_db),
) -> models.User:
"""
Dependency to get current authenticated user from JWT token.
Usage in routes:
@router.get("/protected")
async def protected_route(user: User = Depends(get_current_user)):
return {"user_id": user.id}
"""
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
# Decode token
payload = service.decode_token(token)
if payload is None:
raise credentials_exception
# Get user ID from token
user_id = payload.get("sub")
if user_id is None:
raise credentials_exception
# Fetch user from database
result = await db.execute(
select(models.User).where(models.User.id == int(user_id))
)
user = result.scalar_one_or_none()
if user is None:
raise credentials_exception
if not user.is_active:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="User is inactive",
)
return user
async def get_current_active_user(
user: models.User = Depends(get_current_user),
) -> models.User:
"""Dependency that ensures user is active (already checked in get_current_user)."""
return user

View File

@@ -0,0 +1,20 @@
"""User database model."""
from datetime import datetime
from sqlalchemy import DateTime, String
from sqlalchemy.orm import Mapped, mapped_column
from src.database import Base
class User(Base):
"""User model for authentication."""
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
email: Mapped[str] = mapped_column(String(255), unique=True, index=True)
hashed_password: Mapped[str] = mapped_column(String(255))
is_active: Mapped[bool] = mapped_column(default=True)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)

View File

@@ -0,0 +1,89 @@
"""Authentication routes - register, login, get current user."""
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from src.auth import models, schemas, service
from src.auth.dependencies import get_current_user
from src.database import get_db
router = APIRouter(prefix="/auth", tags=["auth"])
@router.post(
"/register",
response_model=schemas.UserResponse,
status_code=status.HTTP_201_CREATED,
)
async def register(
user_in: schemas.UserCreate,
db: AsyncSession = Depends(get_db),
):
"""Register a new user."""
# Check if email already exists
result = await db.execute(
select(models.User).where(models.User.email == user_in.email)
)
if result.scalar_one_or_none():
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Email already registered",
)
# Create user
user = models.User(
email=user_in.email,
hashed_password=service.hash_password(user_in.password),
)
db.add(user)
await db.commit()
await db.refresh(user)
return user
@router.post("/login", response_model=schemas.Token)
async def login(
form_data: OAuth2PasswordRequestForm = Depends(),
db: AsyncSession = Depends(get_db),
):
"""
Login and get access token.
Note: OAuth2PasswordRequestForm expects 'username' field,
but we use it for email.
"""
# Find user by email (username field)
result = await db.execute(
select(models.User).where(models.User.email == form_data.username)
)
user = result.scalar_one_or_none()
# Verify credentials
if not user or not service.verify_password(
form_data.password, user.hashed_password
):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",
headers={"WWW-Authenticate": "Bearer"},
)
if not user.is_active:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="User is inactive",
)
# Create access token
access_token = service.create_access_token(data={"sub": str(user.id)})
return schemas.Token(access_token=access_token)
@router.get("/me", response_model=schemas.UserResponse)
async def get_me(current_user: models.User = Depends(get_current_user)):
"""Get current authenticated user."""
return current_user

View File

@@ -0,0 +1,33 @@
"""Pydantic schemas for authentication."""
from pydantic import BaseModel, ConfigDict, EmailStr, Field
class UserCreate(BaseModel):
"""Schema for user registration."""
email: EmailStr
password: str = Field(..., min_length=8, description="Minimum 8 characters")
class UserResponse(BaseModel):
"""Schema for user response (no password)."""
id: int
email: str
is_active: bool
model_config = ConfigDict(from_attributes=True)
class Token(BaseModel):
"""JWT token response."""
access_token: str
token_type: str = "bearer"
class TokenData(BaseModel):
"""Decoded token data."""
user_id: int | None = None

View File

@@ -0,0 +1,42 @@
"""Authentication service - password hashing and JWT tokens."""
from datetime import datetime, timedelta
from jose import JWTError, jwt
from passlib.context import CryptContext
from src.config import settings
# Password hashing
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def hash_password(password: str) -> str:
"""Hash a password using bcrypt."""
return pwd_context.hash(password)
def verify_password(plain_password: str, hashed_password: str) -> bool:
"""Verify a password against its hash."""
return pwd_context.verify(plain_password, hashed_password)
def create_access_token(data: dict, expires_delta: timedelta | None = None) -> str:
"""Create a JWT access token."""
to_encode = data.copy()
expire = datetime.utcnow() + (
expires_delta or timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
)
to_encode.update({"exp": expire})
return jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
def decode_token(token: str) -> dict | None:
"""Decode and verify a JWT token. Returns None if invalid."""
try:
payload = jwt.decode(
token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]
)
return payload
except JWTError:
return None

View File

@@ -0,0 +1,26 @@
"""Application configuration using Pydantic Settings."""
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
"""Application settings loaded from environment variables."""
# Database
DATABASE_URL: str = "sqlite+aiosqlite:///./database.db"
# JWT Authentication
SECRET_KEY: str = "change-this-secret-key-in-production"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
ALGORITHM: str = "HS256"
# App
APP_NAME: str = "My API"
DEBUG: bool = False
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
settings = Settings()

View File

@@ -0,0 +1,36 @@
"""Database configuration with async SQLAlchemy 2.0."""
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.orm import DeclarativeBase
from src.config import settings
# Create async engine
engine = create_async_engine(
settings.DATABASE_URL,
echo=settings.DEBUG,
)
# Session factory
async_session = async_sessionmaker(
engine,
class_=AsyncSession,
expire_on_commit=False,
)
class Base(DeclarativeBase):
"""Base class for all SQLAlchemy models."""
pass
async def get_db():
"""Dependency that provides a database session."""
async with async_session() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise

View File

@@ -0,0 +1,62 @@
"""FastAPI application entry point."""
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from src.config import settings
from src.database import Base, engine
# Import routers
from src.auth.router import router as auth_router
# Add more routers as needed:
# from src.items.router import router as items_router
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan handler for startup/shutdown."""
# Startup: Create database tables
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
yield
# Shutdown: Add cleanup here if needed
app = FastAPI(
title=settings.APP_NAME,
lifespan=lifespan,
)
# CORS middleware - configure for your frontend
app.add_middleware(
CORSMiddleware,
allow_origins=[
"http://localhost:3000", # React dev server
"http://localhost:5173", # Vite dev server
],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Include routers
app.include_router(auth_router)
# app.include_router(items_router)
@app.get("/")
async def root():
"""Health check endpoint."""
return {"status": "ok", "app": settings.APP_NAME}
@app.get("/health")
async def health():
"""Detailed health check."""
return {
"status": "healthy",
"database": "connected",
}