chore: initial project setup

Phase 0 — full project scaffold with:
- Backend: FastAPI + SQLAlchemy 2.0 async + Alembic + PostgreSQL 16
- Frontend: React 18 + TypeScript + Vite + Tailwind CSS + shadcn/ui
- Docker Compose (prod + dev override with hot-reload)
- Health endpoint, CORS config, API proxy, env template

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nox (OpenClaw)
2026-03-17 15:20:50 +00:00
parent 6895609edc
commit d8c2048a9b
33 changed files with 751 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
import { Routes, Route } from "react-router-dom";
import HomePage from "./pages/HomePage";
export default function App() {
return (
<Routes>
<Route path="/" element={<HomePage />} />
</Routes>
);
}
+8
View File
@@ -0,0 +1,8 @@
import axios from "axios";
export const apiClient = axios.create({
baseURL: "/api",
headers: {
"Content-Type": "application/json",
},
});
View File
View File
+37
View File
@@ -0,0 +1,37 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 221.2 83.2% 53.3%;
--radius: 0.5rem;
}
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
font-feature-settings: "rlig" 1, "calt" 1;
}
}
+25
View File
@@ -0,0 +1,25 @@
import React from "react";
import ReactDOM from "react-dom/client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import "./index.css";
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000,
retry: 1,
},
},
});
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<App />
</BrowserRouter>
</QueryClientProvider>
</React.StrictMode>,
);
+25
View File
@@ -0,0 +1,25 @@
import { useQuery } from "@tanstack/react-query";
import { apiClient } from "../api/client";
export default function HomePage() {
const { data: health } = useQuery({
queryKey: ["health"],
queryFn: () => apiClient.get("/health").then((r) => r.data),
});
return (
<div className="flex min-h-screen flex-col items-center justify-center bg-background text-foreground">
<div className="text-center">
<h1 className="text-4xl font-bold tracking-tight">Budget Tracker</h1>
<p className="mt-4 text-lg text-muted-foreground">
Gérez votre budget personnel en toute simplicité.
</p>
{health && (
<p className="mt-2 text-sm text-muted-foreground">
API: {health.status}
</p>
)}
</div>
</div>
);
}
+1
View File
@@ -0,0 +1 @@
/// <reference types="vite/client" />