Skip to main content

Locations

Introduction

The Locations module provides read-only access to Indonesian province and city data. Data is sourced from pipe-delimited seed files on disk, not from the database. This feature is used by the frontend for organization address selection and asset location assignment. Business logic is encapsulated in LocationService.


Controller

File: API/Controllers/Locations/LocationsController.cs Route: api/locations Inherits: ControllerBase Auth: None (public endpoints) Delegates to: ILocationService

Endpoints

EndpointMethodAuthDescription
api/locations/provincesGETPublicList all provinces ordered by name
api/locations/provinces/{provinceId}/citiesGETPublicList cities in a specific province
api/locations/citiesGETPublicSearch all cities with optional filters

Query Parameters (GET cities)

ParameterTypeRequiredDescription
searchstringNoFilter by city name (case-insensitive contains)
provinceIdintNoFilter by province ID

Response Format

All endpoints return the standard ApiEnvelope response:

{
"success": true,
"data": {
"items": [...],
"count": 42
},
"errors": []
}

Service

File: Infrastructure/Services/LocationService.cs Interface: ILocationService Lifetime: Scoped

Data Source

Location data is loaded from pipe-delimited text files in the Seed/ directory:

FileSizeContent
province.txt~1 KBProvince data (34 provinces)
city.txt~14 KBCity/regency data

Additional seed files exist (country.txt, district.txt, subdistricts.txt) but are not currently used by the API.

File Format

province.txt: id|unknown|code|name|abbreviation

city.txt: id|province_id|type_code|unknown|code|name|unknown

  • type_code: 1 = Kabupaten (regency), other = Kota (city)

Service Methods

MethodReturnsDescription
GetProvinces()IReadOnlyList<ProvinceDto>All provinces, ordered by name
GetCitiesByProvince(int)IReadOnlyList<CityDto>Cities in a province, ordered by name
GetAllCities(string?, int?)IReadOnlyList<CityDto>Filterable city search, ordered by name

DTOs

File: Application/DTOs/LocationDtos.cs

public sealed record ProvinceDto(int Id, string Code, string Name, string Abbreviation);

public sealed record CityDto(int Id, int ProvinceId, string Type, string Code, string Name, string FullName);
  • CityDto.Type: Either "Kabupaten" or "Kota"
  • CityDto.FullName: Prefixed with type, e.g. "Kabupaten Bandung", "Kota Bandung"

Design Notes

  1. No database dependency — Location data is static and read from disk files, keeping the database focused on dynamic entities.
  2. Synchronous reads — File I/O is performed synchrounously since the data files are small
  3. No caching — Files are re-read on every request. Given the small file sizes and typical call frequency, this is acceptable but could be optimized with an in-memory cache.
  4. No authentication — Location endpoints are public since they contain only reference data.

Future Improvements

Open

  • Add in-memory caching to avoid re-reading seed files on every request.
  • Support district and subdistrict lookups using existing seed data.