Initial scaffold: full-stack RackMapper application

Complete project scaffold with working auth, REST API, Prisma/SQLite
schema, Docker config, and React frontend for both Rack Planner and
Service Mapper modules. Both server and client pass TypeScript strict
mode with zero errors. Initial migration applied.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-21 21:48:56 -05:00
parent 61a4d37d94
commit 231de3d005
79 changed files with 12983 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
import { create } from 'zustand';
import type { ServiceMap, ServiceMapSummary } from '../types';
import { apiClient } from '../api/client';
interface MapState {
maps: ServiceMapSummary[];
activeMap: ServiceMap | null;
loading: boolean;
fetchMaps: () => Promise<void>;
loadMap: (id: string) => Promise<void>;
createMap: (name: string, description?: string) => Promise<ServiceMap>;
deleteMap: (id: string) => Promise<void>;
setActiveMap: (map: ServiceMap | null) => void;
}
export const useMapStore = create<MapState>((set) => ({
maps: [],
activeMap: null,
loading: false,
fetchMaps: async () => {
set({ loading: true });
try {
const maps = await apiClient.maps.list();
set({ maps, loading: false });
} catch {
set({ loading: false });
throw new Error('Failed to load maps');
}
},
loadMap: async (id) => {
set({ loading: true });
try {
const map = await apiClient.maps.get(id);
set({ activeMap: map, loading: false });
} catch {
set({ loading: false });
throw new Error('Failed to load map');
}
},
createMap: async (name, description) => {
const map = await apiClient.maps.create({ name, description });
set((s) => ({ maps: [{ id: map.id, name: map.name, description: map.description, createdAt: map.createdAt, updatedAt: map.updatedAt }, ...s.maps] }));
return map;
},
deleteMap: async (id) => {
await apiClient.maps.delete(id);
set((s) => ({
maps: s.maps.filter((m) => m.id !== id),
activeMap: s.activeMap?.id === id ? null : s.activeMap,
}));
},
setActiveMap: (map) => set({ activeMap: map }),
}));