Initial commit: SQL audit platform v0.1.0

FastAPI backend with auth, user, instance, ticket, query, dashboard APIs.
React + TypeScript frontend with mock data UI (10 pages).
SQLite + async SQLAlchemy, JWT auth, role-based access control.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
loganandClaude Opus 4.7 committed 2026-05-22 11:11:57 +08:00
commit 439155c92e
290 files changed
+61950

No files matched your search

+28
View File
@@ -0,0 +1,28 @@
import request from './request';
export interface LoginResponse {
access_token: string;
token_type: string;
user: {
id: number;
username: string;
display_name: string;
role: string;
email: string | null;
};
}
export interface MeResponse {
id: number;
username: string;
display_name: string;
role: string;
email: string | null;
}
export const authApi = {
login: (username: string, password: string) =>
request.post<any, LoginResponse>('/auth/login', { username, password }),
getMe: () => request.get<any, MeResponse>('/auth/me'),
logout: () => request.post('/auth/logout'),
};
+5
View File
@@ -0,0 +1,5 @@
import request from './request';
export const dashboardApi = {
getStats: () => request.get<any, any>('/dashboard/stats'),
};
+12
View File
@@ -0,0 +1,12 @@
import request from './request';
export const instanceApi = {
list: (params?: any) => request.get<any, any[]>('/instances', { params }),
get: (id: number) => request.get<any, any>(`/instances/${id}`),
create: (data: any) => request.post<any, any>('/instances', data),
update: (id: number, data: any) => request.put<any, any>(`/instances/${id}`, data),
delete: (id: number) => request.delete(`/instances/${id}`),
testConnection: (id: number) => request.post<any, any>(`/instances/${id}/test`),
listDatabases: (id: number) => request.get<any, string[]>(`/instances/${id}/databases`),
listTables: (id: number, db: string) => request.get<any, any[]>(`/instances/${id}/databases/${db}/tables`),
};
+6
View File
@@ -0,0 +1,6 @@
import request from './request';
export const queryApi = {
execute: (data: { instance_id: number; database?: string; sql: string }) =>
request.post<any, any>('/query', data),
};
+27
View File
@@ -0,0 +1,27 @@
import axios from 'axios';
const request = axios.create({
baseURL: '/api/v1',
timeout: 30000,
});
request.interceptors.request.use((config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
request.interceptors.response.use(
(response) => response.data,
(error) => {
if (error.response?.status === 401) {
localStorage.removeItem('token');
window.location.href = '/login';
}
return Promise.reject(error);
}
);
export default request;
+11
View File
@@ -0,0 +1,11 @@
import request from './request';
export const ticketApi = {
list: (params?: any) => request.get<any, any>('/tickets', { params }),
get: (id: number) => request.get<any, any>(`/tickets/${id}`),
create: (data: any) => request.post<any, any>('/tickets', data),
review: (id: number, data: { action: 'approve' | 'reject'; comment: string }) =>
request.post<any, any>(`/tickets/${id}/review`, data),
execute: (id: number) => request.post<any, any>(`/tickets/${id}/execute`),
statistics: () => request.get('/tickets/statistics'),
};
+9
View File
@@ -0,0 +1,9 @@
import request from './request';
export const userApi = {
list: (params?: any) => request.get<any, any[]>('/users', { params }),
get: (id: number) => request.get<any, any>(`/users/${id}`),
create: (data: any) => request.post<any, any>('/users', data),
update: (id: number, data: any) => request.put<any, any>(`/users/${id}`, data),
delete: (id: number) => request.delete(`/users/${id}`),
};