About the project
The task was to preserve the original GIS interface while removing corporate endpoints and data and providing a safe public workflow. The demo supports viewing, editing, export, bulk import and import scoped to the selected territory.
A frontend GIS for settlement and territory boundaries. MapLibre renders the map, while React and MobX connect the list, detail card, geometry editor and import flow. The public in-memory adapter reproduces the backend contract with synthetic data and complete validation in both import modes.
What sets the implementation apart
Bulk mode reads OKTMO from each feature with a contextual fallback. Settlement mode forces the opened card OKTMO and keeps a separate file list. Polygon and MultiPolygon pass CRS, size, vertex and topology checks; invalid geometry can be edited or skipped, and reapplying a file does not duplicate objects.
Application-code composition
Shares use Git application-file bytes at pinned revisions. Each file belongs to one subsystem under scripts/generate-stack-share.mjs rules; tests, assets, dependencies and generated files are excluded. Rounded to 0.1%. This describes code composition, not proficiency.
- Only the backend is replaced with tab memory. The server-side OData/PostGIS service is not connected; the original repository remains private.
- Adapter limits: 20 files, 500 polygons per file, 1,000 per session; file text up to 5 MB. Polygon/MultiPolygon and EPSG:4326/3857 are supported.
- Imported data disappears after reloading. GeoJSON export lets you save the result locally.
- OpenStreetMap tiles load from an external server. The basemap needs that server to be available.
- OSM boundaries are simplified for editing and are not cadastral data. Cities use place=city/town outlines; districts and regions use boundary=administrative. OKTMO codes are for demonstration. The source and ODbL license are stated in the demo and downloadable GeoJSON.
Screenshots, diagrams and source evidence retain their original language; captions and descriptions are translated.
Architecture and diagrams
- The original sppi-dark theme: dark background, yellow controls and original status colors.
- MapLibre loads standard OpenStreetMap tiles. Attribution is included; bulk map downloads and offline caching are not implemented.
- The original FilesScreen → PolygonsScreen → PolygonEditScreen flow runs through a local adapter for OData and geo-import contracts.
- Imports are validated and previewed first. Applying an import transfers only valid polygons to the main editor; applying it again does not duplicate the same importId.
- Standalone styles share the .sppi-dark scope: original colors, consistent SVG icons, 40 px actions and responsive file cards. ResizeObserver keeps MapLibre in sync with panel and viewport changes.
- OpenStreetMap outlines are simplified with topology preserved: 54 territories, 21,421 vertices and 7 MultiPolygons. Regions, districts and cities have different opacity; original control and status colors are preserved.
Code map: files and dependencies
This map is tied to version 5c5466fa43e6. The table lists the screen or API, related module and data.
| Feature | Screen / API | Module | Data / verification |
|---|---|---|---|
| Map and theme | Main editor | src_front/src/demo/config.ts; styles/themes/sppi-dark.scss | MapLibre, OSM, 54 territories and opacity of nested boundaries |
| Bulk upload | File import → /geo-import/import | modules/import/screens/FilesScreen.tsx; demo/import-api.ts | GeoJSON, CRS, WKB; file with 54 real outlines |
| Validation and application | Polygon list → /geo-import/files/:id/apply | PolygonsScreen.tsx; ImportRepository; import-api.ts | statuses, skipping, validation; 53 applied, 107 in the export |
| Editing | Polygon editing → /polygons/:id/save | PolygonEditScreen.tsx; MapImportMapHelper | Mapbox Draw; original/default WKB |
| Isolation and export | Main screen | demo/data.ts; demo/Controls.tsx | EventTarget, tab memory; GeoJSON export and reset |
| Visual system | All screens and states | demo/foundation.css; demo/original-theme.css | SVG masks, fields, buttons, tables; visual QA |
| Map size | Main editor and import | utils/observe-map-resize.ts; MapEditor.tsx; MapImport.tsx | ResizeObserver, requestAnimationFrame, cleanup; canvas dimensions |
| Import layers | Basemap menu | MapImportLayersSwitcher.tsx; map-import.controller.ts | initial visibility synchronized with the store; original checkbox |
| Import editor spacing | Polygon editing | PolygonEditScreen.tsx; demo/original-theme.css | import-polygon-editor: shared 12 px padding; field/button coordinates and saving |
| Dataset and provenance | Map / download dataset | demo/russia-boundaries.json; demo/data.ts | OSM relations, ODbL, demo OKTMO codes, Polygon/MultiPolygon |
| Combined boundary | Import record and map | geometryBbox; getUnitedPolygons; validatePolygons; MapImport.tsx | bounding box of all parts; selected territory stays in focus after loading |
Using the code map
- Before making a change, find the feature and trace its links to the API, state and storage.
- Check inputs, errors, repeated events and dependent workflows.
- After making a change, update the map and affected diagrams alongside the code.
- Run the related checks and link the new evidence to the source version.
Workflows and API
- Find Vladimir, Suzdal, Nizhny Novgorod, Suzdalsky District or Vladimir Oblast; open its record and zoom to the outline.
- Download the 54-territory dataset, upload it through bulk import and validate all geometries.
- Open a file: polygon list, statuses, filters and a map of the combined boundaries.
- Open a polygon: edit it, restore the original geometry, explicitly skip it and save.
- Fix or skip errors, select “Apply import”, close the module and export the result from the main editor.
- Reset the example; check that another tab did not receive the imported files.
Verification of the published version
CI: GIS build with 54 territories and editor focus ↗ · 4108a165 · this demo's version · 2026-09-07
CI: Build after aligning the import editor ↗ · 9d0df859 · historical run of a different version · 2026-09-07
CI: GIS production build after the interface update ↗ · f8cf0051 · historical run of a different version · 2026-09-07
- Published revision 4108a165: 54 named territories, five city/region/district records, search and empty results; exported initial coordinates match the dataset.
- Bulk import of 54 territories: all geometries valid. Saving a multipart polygon, skipping one territory and applying 53; applying again does not create duplicates. Export contains 107 objects and source links.
- Self-intersection prevents applying the import. Another session does not receive the files; reset restores the original 54 objects.
- A vertex of the Suzdal outline was moved with the pointer. The saved geometry change was confirmed in the export; the other 53 objects were unchanged.
- Desktop 1440×1000 and mobile 390×844 / 360×844: no horizontal overflow or JavaScript errors. The mobile editor shows the selected territory's OKTMO code; left/right field edges differ by no more than 1 px.
- Vite build and GitHub CI passed. The complete legacy TypeScript/lint suite is outside this verification.
These checks apply to the listed version. Business metrics and model quality on an independent dataset were not measured.
Measurements
- The static build is served by shared Nginx; GIS has no separate backend process on the VPS.
- 54 objects; 21,421 vertices after simplification, 76–926 per object, up to 480 per ring. These describe the dataset, not boundary accuracy.
- In one Chromium check of the published version: first list 1.80 s, import of 54 territories 0.66 s. This measures the interface on the test machine; it is not a load test or an SLA.
Running and operating
Build: src_front, npm ci --ignore-scripts; npm run build:demo. The artifact is built in GitHub CI and published as a static Nginx release.
The backend adapter lives in demo/api.ts and demo/import-api.ts. Connecting a real API requires implementing the import-application contract and replacing the local transport.
Geometry checks use the existing validation.util.ts; WKB conversion uses wkx. Visitors' GeoJSON is not uploaded to the VPS.
Before a change, trace the feature through its screen, ImportRepository, adapter, geometry and state. Afterwards, update the code-map and check upload, errors, skipping, applying, export and reset.
Visual update, 7 September 2026: CSS is loaded after the original components; specificity is scoped to the theme. Text buttons do not inherit icon-only dimensions. On narrow screens, the import layout is vertical; opening a modal locks background scrolling. OpenStreetMap tiles remain external and may load as the map zoom changes.
Alignment update, 7 September 2026: the import editor uses one 12 px padding container. Conflicting utility classes and the single-card scrollbar reservation were removed; the footer and OKTMO field share the same width. The change is limited to PolygonEditScreen.
Geographic dataset: demo/russia-boundaries.json, OpenStreetMap snapshot from 7 September 2026, 11:09:36 UTC. Each territory retains its relation URL, type, date and simplification tolerance. The derived dataset is available under ODbL through download and export.
Bounding boxes include every ring and MultiPolygon part. They are recalculated on save and import. The selected territory remains in focus after the map loads; the import editor displays that territory's own OKTMO code.
Stack
| React / MobX | Original screens, state and import |
|---|---|
| MapLibre / Mapbox Draw | Map basemap, layers and geometry editing |
| GeoJSON / WKB | Validation, upload and export |
Materials and source code
Repository history: since February 2025. Public demo: 7 September 2026.
The evidence archive retains its original language.