23 lines
4.5 KiB
JavaScript
23 lines
4.5 KiB
JavaScript
import fs from 'node:fs';
|
|
const id = { name: 'id', in: 'path', required: true, schema: { type: 'string', format: 'uuid' } };
|
|
const string = { type: 'string' };
|
|
const schema = properties => ({ type: 'object', properties });
|
|
const paths = {};
|
|
const operation = (summary, parameters = [], body = null) => ({ summary, security: [{ laravelSession: [] }], parameters: [...parameters, ...(body ? [{ name: 'Idempotency-Key', in: 'header', required: true, schema: { type: 'string', format: 'uuid' } }] : [])],
|
|
...(body ? { requestBody: { required: true, content: { 'application/json': { schema: body } } } } : {}),
|
|
responses: Object.fromEntries([200, ...(summary.startsWith('Create source') ? [201] : []), 401, 403, 404, 409, 422, 429].map(code => [code, { description: code < 300 ? 'JSON result with X-Correlation-ID; private, no-store' : 'Request rejected; validation and workflow errors use Problem Details within territorial middleware' }])) });
|
|
for (const collection of ['countries','provinces','districts','admin-posts','localities','search']) paths['/'+collection] = { get: operation('Read currently published territories: '+collection,
|
|
['q','cursor','parent_id','country_id','province_id','district_id','admin_post_id'].map(name => ({ name, in: 'query', schema: string })).concat([{ name: 'limit', in: 'query', schema: { type: 'integer', minimum: 1, maximum: 100 } }])) };
|
|
paths['/territories/{type}/{id}'] = { get: operation('Read published territory and translated names', [id, { name: 'type', in: 'path', required: true, schema: { enum: ['country','province','district','admin_post','locality'] } }]) };
|
|
const territory = schema({ name: string, code: string, location_type: { enum: ['country','province','district','admin_post','locality'] }, parent_id: { type: ['string','null'], format: 'uuid' }, source_id: { type: 'string', format: 'uuid' }, valid_from: { type: 'string', format: 'date' }, valid_to: { type: ['string','null'], format: 'date' }, reason: { type: 'string', minLength: 10, maxLength: 1000 } });
|
|
territory.required = ['name','code','location_type','source_id','valid_from','reason'];
|
|
paths['/territories'] = { post: operation('Create private territorial draft; designated editor with MFA', [], territory) };
|
|
paths['/territories/{id}'] = { patch: operation('Replace draft attributes and invalidate editorial approvals', [id], { ...territory, required: [...territory.required,'version_no'], properties: { ...territory.properties, version_no: { type: 'integer', minimum: 1 } } }) };
|
|
paths['/territories/{id}/transitions'] = { post: operation('Submit, review, publish, reject or archive; independent actors required', [id], { ...schema({ action: { enum: ['pending_review','approved','published','rejected','archived'] }, version_no: { type: 'integer', minimum: 1 }, reason: { type: 'string', minLength: 10 } }), required: ['action','version_no','reason'] }) };
|
|
paths['/sources'] = { post: operation('Create source in pending state', [], { ...schema({ name: string, responsible_entity: string, reference: string, license: string, checksum: { type: 'string', pattern: '^[0-9a-f]{64}$' }, source_version: string, collected_at: { type: 'string', format: 'date' }, original_crs: string }), required: ['name','reference','checksum','source_version','collected_at'] }) };
|
|
paths['/sources/{id}/transitions'] = { post: operation('Independent source approval or revocation with evidence reference', [id], { ...schema({ action: { enum: ['approved','revoked'] }, approval_reference: { type: 'string', minLength: 10 } }), required: ['action','approval_reference'] }) };
|
|
paths['/sources'].get = operation('Management-only source metadata and decision evidence, MFA required');
|
|
paths['/drafts'] = { get: operation('Management-only territorial editorial records, MFA required') };
|
|
fs.writeFileSync('docs/investmoz/gis/territorial-openapi.json', JSON.stringify({ openapi: '3.1.0', info: { title: 'InvestMoz territorial registry — implemented subset', version: '0.1.0', description: 'Local session adapter. OAuth/OIDC, geometric queries, assignments, imports, hierarchy endpoint and administrative UI remain unimplemented. Response schemas require expansion before external certification.' }, servers: [{ url: '/api/v1/geo' }], paths, components: { securitySchemes: { laravelSession: { type: 'apiKey', in: 'cookie', name: 'deployment_session_cookie', description: 'Actual name configured by Laravel; write requests also require Laravel CSRF/origin protection. This is not OAuth/OIDC.' } } } }, null, 2)+'\n');
|
|
console.log('Territorial OpenAPI: '+Object.keys(paths).length+' paths');
|