397 lines
12 KiB
Nix
397 lines
12 KiB
Nix
{
|
|
description = "Reference Board Viewer - Web-based visual reference management";
|
|
|
|
inputs = {
|
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
|
nixos-generators = {
|
|
url = "github:nix-community/nixos-generators";
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
};
|
|
|
|
outputs =
|
|
{
|
|
self,
|
|
nixpkgs,
|
|
nixos-generators,
|
|
}:
|
|
let
|
|
system = "x86_64-linux";
|
|
pkgs = nixpkgs.legacyPackages.${system};
|
|
|
|
# Shared Python dependencies - used by both dev environment and package
|
|
pythonDeps =
|
|
ps: withTests:
|
|
with ps;
|
|
[
|
|
# Core backend dependencies
|
|
fastapi
|
|
uvicorn
|
|
sqlalchemy
|
|
alembic
|
|
pydantic
|
|
pydantic-settings # Settings management
|
|
psycopg2 # PostgreSQL driver (sync)
|
|
asyncpg # PostgreSQL driver (async)
|
|
# Auth & Security
|
|
python-jose
|
|
passlib
|
|
bcrypt # Password hashing backend for passlib
|
|
email-validator # Email validation for pydantic
|
|
# Image processing
|
|
pillow
|
|
python-magic # File type detection via magic bytes
|
|
# Storage
|
|
boto3
|
|
# HTTP & uploads
|
|
httpx
|
|
python-multipart
|
|
]
|
|
++ (
|
|
if withTests then
|
|
[
|
|
# Testing (dev only)
|
|
pytest
|
|
pytest-cov
|
|
pytest-asyncio
|
|
]
|
|
else
|
|
[ ]
|
|
);
|
|
|
|
pythonEnv = pkgs.python3.withPackages (ps: pythonDeps ps true);
|
|
in
|
|
{
|
|
# Development shell
|
|
devShells.${system}.default = pkgs.mkShell {
|
|
buildInputs = with pkgs; [
|
|
# Python environment
|
|
pythonEnv
|
|
uv
|
|
ruff
|
|
|
|
# Database
|
|
postgresql
|
|
|
|
# Frontend
|
|
nodejs
|
|
nodePackages.npm
|
|
eslint
|
|
|
|
# Image processing
|
|
imagemagick
|
|
file # Required for python-magic to detect file types
|
|
|
|
# Storage
|
|
minio
|
|
minio-client
|
|
|
|
# Development tools
|
|
git
|
|
direnv
|
|
tmux
|
|
];
|
|
|
|
shellHook = ''
|
|
echo "🚀 Reference Board Viewer Development Environment"
|
|
echo ""
|
|
echo "📦 Versions:"
|
|
echo " Python: $(python --version)"
|
|
echo " Node.js: $(node --version)"
|
|
echo " PostgreSQL: $(psql --version | head -n1)"
|
|
echo " MinIO: $(minio --version | head -n1)"
|
|
echo ""
|
|
echo "🔧 Development Services:"
|
|
echo " Start: ./scripts/dev-services.sh start"
|
|
echo " Stop: ./scripts/dev-services.sh stop"
|
|
echo " Status: ./scripts/dev-services.sh status"
|
|
echo ""
|
|
echo "📚 Quick Commands:"
|
|
echo " Dev (tmux): nix run .#dev"
|
|
echo " Backend: cd backend && uvicorn app.main:app --reload"
|
|
echo " Frontend: cd frontend && npm run dev"
|
|
echo " Database: psql -h localhost -U webref webref"
|
|
echo " Tests: cd backend && pytest --cov"
|
|
echo ""
|
|
echo "📖 Documentation:"
|
|
echo " API Docs: http://localhost:8000/docs"
|
|
echo " App: http://localhost:5173"
|
|
echo " MinIO UI: http://localhost:9001"
|
|
echo ""
|
|
|
|
# Set up environment variables
|
|
export DATABASE_URL="postgresql://webref@localhost:5432/webref"
|
|
export MINIO_ENDPOINT="localhost:9000"
|
|
export MINIO_ACCESS_KEY="minioadmin"
|
|
export MINIO_SECRET_KEY="minioadmin"
|
|
export PYTHONPATH="$PWD/backend:$PYTHONPATH"
|
|
'';
|
|
};
|
|
|
|
# Apps - Scripts that can be run with `nix run`
|
|
apps.${system} = {
|
|
default = {
|
|
type = "app";
|
|
program = "${pkgs.writeShellScript "help" ''
|
|
echo "Available commands:"
|
|
echo " nix run .#dev - Start backend + frontend in tmux"
|
|
echo " nix run .#lint - Run all linting checks"
|
|
echo " nix run .#lint-backend - Run backend linting only"
|
|
echo " nix run .#lint-frontend - Run frontend linting only"
|
|
echo " nix run .#lint-fix - Auto-fix linting issues"
|
|
''}";
|
|
};
|
|
|
|
# Development runner with tmux
|
|
dev = {
|
|
type = "app";
|
|
program = "${pkgs.writeShellScript "dev-tmux" ''
|
|
set -e
|
|
|
|
# Check if we're in the project root
|
|
if [ ! -d "backend" ] || [ ! -d "frontend" ]; then
|
|
echo "❌ Error: Not in project root directory"
|
|
echo "Please run this command from the webref project root"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if frontend dependencies are installed
|
|
if [ ! -d "frontend/node_modules" ]; then
|
|
echo "📦 Installing frontend dependencies..."
|
|
cd frontend
|
|
${pkgs.nodejs}/bin/npm install
|
|
cd ..
|
|
fi
|
|
|
|
# Set environment variables
|
|
export DATABASE_URL="postgresql://webref@localhost:5432/webref"
|
|
export MINIO_ENDPOINT="localhost:9000"
|
|
export MINIO_ACCESS_KEY="minioadmin"
|
|
export MINIO_SECRET_KEY="minioadmin"
|
|
export PYTHONPATH="$PWD/backend:$PYTHONPATH"
|
|
export PATH="${pythonEnv}/bin:${pkgs.nodejs}/bin:$PATH"
|
|
|
|
# Session name
|
|
SESSION_NAME="webref-dev"
|
|
|
|
# Kill existing session if it exists
|
|
${pkgs.tmux}/bin/tmux has-session -t $SESSION_NAME 2>/dev/null && ${pkgs.tmux}/bin/tmux kill-session -t $SESSION_NAME
|
|
|
|
echo "🚀 Starting development environment in tmux..."
|
|
echo ""
|
|
echo "📋 Tmux Controls:"
|
|
echo " Switch panes: Ctrl+b → arrow keys"
|
|
echo " Scroll mode: Ctrl+b → ["
|
|
echo " Exit scroll: q"
|
|
echo " Detach session: Ctrl+b → d"
|
|
echo " Kill session: Ctrl+b → :kill-session"
|
|
echo ""
|
|
echo "Starting in 2 seconds..."
|
|
sleep 2
|
|
|
|
# Create new tmux session with backend
|
|
${pkgs.tmux}/bin/tmux new-session -d -s "$SESSION_NAME" -n "webref" -c "$PWD/backend" \
|
|
"printf '\n🐍 Starting Backend (uvicorn)...\n\n' && ${pythonEnv}/bin/uvicorn app.main:app --reload --host 0.0.0.0 --port 8000; read -p 'Backend stopped. Press Enter to exit...'"
|
|
|
|
# Split window vertically and run frontend
|
|
${pkgs.tmux}/bin/tmux split-window -h -t "$SESSION_NAME":0 -c "$PWD/frontend" \
|
|
"printf '\n⚡ Starting Frontend (Vite)...\n\n' && ${pkgs.nodejs}/bin/npm run dev; read -p 'Frontend stopped. Press Enter to exit...'"
|
|
|
|
# Set pane titles
|
|
${pkgs.tmux}/bin/tmux select-pane -t "$SESSION_NAME":0.0 -T "Backend (uvicorn)"
|
|
${pkgs.tmux}/bin/tmux select-pane -t "$SESSION_NAME":0.1 -T "Frontend (vite)"
|
|
|
|
# Balance panes
|
|
${pkgs.tmux}/bin/tmux select-layout -t "$SESSION_NAME":0 even-horizontal
|
|
|
|
# Focus on backend pane
|
|
${pkgs.tmux}/bin/tmux select-pane -t "$SESSION_NAME":0.0
|
|
|
|
# Attach to session
|
|
${pkgs.tmux}/bin/tmux attach-session -t "$SESSION_NAME"
|
|
''}";
|
|
};
|
|
|
|
# Unified linting - calls both backend and frontend lints
|
|
lint = {
|
|
type = "app";
|
|
program = "${pkgs.writeShellScript "lint" ''
|
|
set -e
|
|
|
|
# Run backend linting
|
|
${self.apps.${system}.lint-backend.program}
|
|
|
|
echo ""
|
|
|
|
# Run frontend linting
|
|
${self.apps.${system}.lint-frontend.program}
|
|
|
|
echo ""
|
|
echo "✅ All linting checks passed!"
|
|
''}";
|
|
};
|
|
|
|
# Auto-fix linting issues
|
|
lint-fix = {
|
|
type = "app";
|
|
program = "${pkgs.writeShellScript "lint-fix" ''
|
|
set -e
|
|
|
|
echo "🔧 Auto-fixing backend Python code..."
|
|
if [ -d "backend" ]; then
|
|
cd backend
|
|
${pkgs.ruff}/bin/ruff check --fix --no-cache app/ || true
|
|
${pkgs.ruff}/bin/ruff format app/
|
|
cd ..
|
|
else
|
|
echo "⚠ Not in project root (backend/ not found)"
|
|
exit 1
|
|
fi
|
|
|
|
if [ -d "frontend/node_modules" ]; then
|
|
echo ""
|
|
echo "🔧 Auto-fixing frontend code..."
|
|
cd frontend
|
|
${pkgs.nodePackages.prettier}/bin/prettier --write src/
|
|
cd ..
|
|
fi
|
|
|
|
echo ""
|
|
echo "✅ Auto-fix complete!"
|
|
''}";
|
|
};
|
|
|
|
# Backend linting only
|
|
lint-backend = {
|
|
type = "app";
|
|
program = "${pkgs.writeShellScript "lint-backend" ''
|
|
set -e
|
|
|
|
echo "🔍 Linting backend Python code..."
|
|
if [ -d "backend" ]; then
|
|
cd backend
|
|
${pkgs.ruff}/bin/ruff check --no-cache app/
|
|
${pkgs.ruff}/bin/ruff format --check app/
|
|
cd ..
|
|
else
|
|
echo "⚠ Not in project root (backend/ not found)"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✅ Backend linting passed!"
|
|
''}";
|
|
};
|
|
|
|
# Frontend linting only
|
|
lint-frontend = {
|
|
type = "app";
|
|
program = "${pkgs.writeShellScript "lint-frontend" ''
|
|
set -e
|
|
|
|
# Add nodejs to PATH for npm scripts
|
|
export PATH="${pkgs.nodejs}/bin:$PATH"
|
|
|
|
echo "🔍 Linting frontend TypeScript/Svelte code..."
|
|
if [ -d "frontend/node_modules" ]; then
|
|
cd frontend
|
|
npm run lint
|
|
${pkgs.nodePackages.prettier}/bin/prettier --check src/
|
|
npm run check
|
|
cd ..
|
|
else
|
|
echo "⚠ Frontend node_modules not found"
|
|
echo "Run 'cd frontend && npm install' first"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✅ Frontend linting passed!"
|
|
''}";
|
|
};
|
|
|
|
# Run development VM
|
|
dev-vm = {
|
|
type = "app";
|
|
program = "${self.packages.${system}.dev-vm}/bin/run-nixos-vm";
|
|
};
|
|
};
|
|
|
|
# Package definitions (for production deployment)
|
|
packages.${system} = {
|
|
# Backend package
|
|
backend = pkgs.python3Packages.buildPythonApplication {
|
|
pname = "webref-backend";
|
|
version = "1.0.0";
|
|
pyproject = true;
|
|
src = ./backend;
|
|
|
|
build-system = with pkgs.python3Packages; [
|
|
setuptools
|
|
];
|
|
|
|
propagatedBuildInputs = pythonDeps pkgs.python3Packages false;
|
|
|
|
meta = {
|
|
description = "Reference Board Viewer - Backend API";
|
|
homepage = "https://github.com/yourusername/webref";
|
|
license = pkgs.lib.licenses.mit;
|
|
};
|
|
};
|
|
|
|
# QEMU VM for development services
|
|
dev-vm = nixos-generators.nixosGenerate {
|
|
system = "x86_64-linux";
|
|
modules = [ ./nixos/dev-services.nix ];
|
|
format = "vm";
|
|
};
|
|
|
|
# VM for CI testing
|
|
ci-vm = nixos-generators.nixosGenerate {
|
|
system = "x86_64-linux";
|
|
modules = [
|
|
./nixos/dev-services.nix
|
|
{
|
|
# CI-specific configuration
|
|
services.openssh.enable = true;
|
|
services.openssh.settings.PermitRootLogin = "yes";
|
|
users.users.root.password = "test";
|
|
}
|
|
];
|
|
format = "vm";
|
|
};
|
|
|
|
# Container for lightweight testing
|
|
dev-container = nixos-generators.nixosGenerate {
|
|
system = "x86_64-linux";
|
|
modules = [ ./nixos/dev-services.nix ];
|
|
format = "lxc";
|
|
};
|
|
|
|
default = self.packages.${system}.backend;
|
|
};
|
|
|
|
# NixOS VM tests
|
|
checks.${system} = import ./nixos/tests.nix { inherit pkgs; };
|
|
|
|
# NixOS configurations
|
|
nixosConfigurations = {
|
|
# Development services VM
|
|
dev-services = nixpkgs.lib.nixosSystem {
|
|
system = "x86_64-linux";
|
|
modules = [
|
|
./nixos/dev-services.nix
|
|
{
|
|
# Minimal system configuration
|
|
fileSystems."/" = {
|
|
device = "tmpfs";
|
|
fsType = "tmpfs";
|
|
options = [ "mode=0755" ];
|
|
};
|
|
boot.loader.systemd-boot.enable = true;
|
|
system.stateVersion = "24.05";
|
|
}
|
|
];
|
|
};
|
|
};
|
|
};
|
|
}
|