glanzlicht / GastroOS
Verified secure showcase
500 Files 1 MB Public size 31 Redacted TypeScript · SQL · JSON · Markdown · DOCKERIGNORE · EXAMPLE

Project overview

GastroOS is a verified code showcase with 500 visible project entries across 3 top-level modules. The primary detected language is TypeScript; protected files remain visible in the structure while their contents stay private.

README

GastravaOS

GastravaOS is a modular Hospitality Operational Intelligence Platform.

The technical repository name remains GastroOS for compatibility. The product is presented publicly as GastravaOS.

Product preview

GastravaOS operations dashboard

GastravaOS is designed for hospitality operations ranging from small venues to larger multi-location organizations. The platform combines operational workflows, resilient data handling and role-specific user experiences without exposing internal complexity to operators.

What this repository demonstrates

This repository is presented as a technical portfolio showcase, not as a complete product blueprint.

It demonstrates work across:

  • backend engineering with Node.js, TypeScript, NestJS and REST/OpenAPI;
  • PostgreSQL data modeling, explicit SQL migrations and transactional consistency;
  • Flutter application architecture with Riverpod, go_router, Drift/SQLite and Dio;
  • operational workflows across hospitality domains;
  • offline-capable client foundations and synchronization patterns;
  • real-time state reconciliation and event-driven integration patterns;
  • integrations for storage, payments, fiscal/accounting systems and external platforms;
  • Docker-based development, CI, observability and runtime verification;
  • tenant-aware security, audit-oriented design and permission boundaries;
  • applied AI around deterministic domain data and human-controlled actions.

Technology stack

AreaTechnology
BackendNode.js 24 LTS, TypeScript, NestJS 11
APIREST / OpenAPI
DatabasePostgreSQL 18, Drizzle ORM, explicit SQL migrations
FrontendFlutter, Riverpod, go_router
Local dataDrift / SQLite
NetworkingDio, json_serializable
InfrastructureDocker Compose, S3-compatible storage
ArchitectureModular monolith, transactional outbox
QualityAutomated tests, CI, observability and runtime verification

Engineering approach

The codebase is organized around clear boundaries and reusable platform capabilities rather than one large feature layer.

Recurring engineering principles include:

  • deterministic and auditable domain state;
  • separation of operational truth from presentation;
  • role- and context-specific interfaces;
  • resilience under intermittent connectivity;
  • explicit integration adapters;
  • composable capabilities instead of duplicated vertical implementations;
  • controlled exposure of sensitive business, security and product logic.

Portfolio boundary

The public showcase intentionally omits detailed roadmaps, ADRs, security internals, commercial logic, AI prompts, operational playbooks and reconstructable product strategy.

Those materials remain in the private repository. The public view is optimized so technical reviewers can evaluate engineering breadth and implementation quality without receiving a reconstruction guide for the product.

Local development

The repository uses a versioned pnpm dependency graph.

corepack enable
pnpm install --frozen-lockfile

Project-specific runtime and verification details remain in the private engineering documentation.

Status

GastravaOS is under active development. The repository contains a broad implementation foundation and ongoing product work rather than a finished commercial release.

The public showcase focuses on engineering capability, architecture quality and implementation breadth while deliberately omitting core IP.

apps/backend/src/modules/exports/workers/export.worker.tsTypeScript
import { Injectable } from '@nestjs/common';
import { PutObjectCommand,S3Client } from '@aws-sdk/client-s3';
import ExcelJS from 'exceljs';
import { randomUUID } from 'node:crypto';
import { DatabaseService } from '../../../infrastructure/database/database.service';
import { OutboxService } from '../../../infrastructure/outbox/outbox.service';
import { ExportAuthorizationService } from '../application/export-authorization.service';
@Injectable()
export class ExportWorker {
private readonly bucket=process.env.OBJECT_STORAGE_BUCKET ?? 'gastro-os';
private readonly s3=new S3Client({
region:process.env.OBJECT_STORAGE_REGION ?? 'local',
endpoint:process.env.OBJECT_STORAGE_ENDPOINT,
forcePathStyle:true,
credentials:{
accessKeyId:process.env.OBJECT_STORAGE_ACCESS_KEY ?? 'minio',
secretAccessKey:process.env.OBJECT_STORAGE_SECRET_KEY ?? 'change-me',
},
});
constructor(
private readonly database:DatabaseService,
private readonly outbox:OutboxService,
private readonly authorization:ExportAuthorizationService,
) {}
async runOne(exportJobId:string) {
const jobs=await this.database.query<any>(
`select * from export_jobs where id=$1 and status='queued'`,
[exportJobId],
);
const job=jobs[0];
if(!job) return {processed:false};
await this.authorization.assertGenerationAllowed(job);
const claimed=await this.database.query<any>(
`update export_jobs
set status='processing',started_at=now()
where id=$1 and status='queued'
returning id`,
[exportJobId],
);
if(!claimed[0]) return {processed:false};
try {
const rows=await this.dataset(job);
const generated=job.format==='xlsx'
? await this.xlsx(rows)
: this.csv(rows);
if(job.format==='pdf') throw new Error('exports.pdf_curated_layout_required');
const mime=job.format==='xlsx'
? 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
: 'text/csv';
const ext=job.format==='xlsx'?'xlsx':'csv';
const assetId=randomUUID();
const key=`org/${job.organization_id}/exports/${randomUUID()}.${ext}`;
await this.s3.send(new PutObjectCommand({
Bucket:this.bucket,Key:key,Body:generated,ContentType:mime,
}));
await this.database.query(
`insert into file_assets(
id,organization_id,location_id,purpose,storage_key,original_file_name,
mime_type,size_bytes,status,created_by_user_id
) values($1,$2,$3,'export_result',$4,$5,$6,$7,'available',$8)`,
[
assetId,job.organization_id,job.location_id,key,
`${job.export_type}-${exportJobId}.${ext}`,mime,
Buffer.byteLength(generated),job.requested_by_user_id,
],
);
await this.database.query(
`update export_jobs
set status='completed',file_asset_id=$1,completed_at=now(),
expires_at=now()+interval '7 days'
where id=$2`,
[assetId,exportJobId],
);
await this.outbox.append({
organizationId:job.organization_id,
aggregateType:'ExportJob',
aggregateId:exportJobId,
eventType:'ExportCompleted',
payload:{exportJobId,fileAssetId:assetId,requestedByUserId:job.requested_by_user_id},
});
return {processed:true,fileAssetId:assetId};
} catch(error:any) {
await this.database.query(
`update export_jobs set status='failed',completed_at=now(),error=$1 where id=$2`,
[String(error?.message??error),exportJobId],
);
await this.outbox.append({
organizationId:job.organization_id,
aggregateType:'ExportJob',
aggregateId:exportJobId,
eventType:'ExportFailed',
payload:{exportJobId,error:String(error?.message??error)},
});
return {processed:true,failed:true};
}
}
private async dataset(job:any):Promise<Record<string,unknown>[]> {
const loc=job.location_id;
switch(job.export_type) {
case 'inventory':
return this.database.query<any>(
`select si.name,sl.name as storage_location,
sbp.quantity_normalized::text as quantity, sbp.normalized_unit_code as unit
from stock_balance_projection sbp
join stock_items si on si.id=sbp.stock_item_id
join storage_locations sl on sl.id=sbp.storage_location_id
where sbp.organization_id=$1 and ($2::uuid is null or sbp.location_id=$2)
order by si.name,sl.name`,
[job.organization_id,loc],
);
case 'waste':
return this.database.query<any>(
`select wr.recorded_at,si.name,wr.normalized_quantity::text as quantity,
wr.normalized_unit_code as unit,wr.reason
from waste_records wr
join stock_items si on si.id=wr.stock_item_id
where wr.organization_id=$1 and ($2::uuid is null or wr.location_id=$2)
order by wr.recorded_at desc limit 100000`,
[job.organization_id,loc],
);
case 'suppliers':
default:
if(job.export_type==='purchasing') {
return this.database.query<any>(
`select gr.received_at,s.name as supplier,gr.receipt_number,
grl.received_quantity::text,grl.purchase_unit_code,
grl.unit_price_minor_snapshot,grl.currency_code
from goods_receipts gr
join suppliers s on s.id=gr.supplier_id
join goods_receipt_lines grl on grl.goods_receipt_id=gr.id
where gr.organization_id=$1 and ($2::uuid is null or gr.location_id=$2)
order by gr.received_at desc limit 100000`,
[job.organization_id,loc],
);
}
if(job.export_type==='incidents') {
return this.database.query<any>(
`select incident_type,severity,status,title,occurred_at,reported_at,resolution
from incidents
where organization_id=$1 and ($2::uuid is null or location_id=$2)
order by reported_at desc limit 100000`,
[job.organization_id,loc],
);
}
if(job.export_type==='safety') {
return this.database.query<any>(
`select sc.business_date,sc.status,sc.result,sc.performed_at,sct.name
from safety_checks sc
join safety_check_templates sct on sct.id=sc.safety_check_template_id
where sc.organization_id=$1 and ($2::uuid is null or sc.location_id=$2)
order by sc.business_date desc limit 100000`,
[job.organization_id,loc],
);
}
if(job.export_type==='employees') {
return this.database.query<any>(
`select id,first_name,last_name,status,created_at
from employees where organization_id=$1 order by last_name,first_name`,
[job.organization_id],
);
}
if(job.export_type==='guests') {
return this.database.query<any>(
`select id,display_name,email,phone,created_at
from guests where organization_id=$1 order by created_at desc limit 100000`,
[job.organization_id],
);
}
if(job.export_type==='audit') {
return this.database.query<any>(
`select occurred_at,event_type,entity_type,entity_id,actor_user_id,metadata
from audit_events where organization_id=$1
order by occurred_at desc limit 100000`,
[job.organization_id],
);
}
return this.database.query<any>(
`select business_date,gross_sales_minor,refunds_minor,order_count,guest_count,
theoretical_food_cost_percent,gross_margin_percent
from reporting_daily_location_kpis
where organization_id=$1 and ($2::uuid is null or location_id=$2)
order by business_date desc limit 10000`,
[job.organization_id,loc],
);
}
}
private csv(rows:Record<string,unknown>[]) {
if(rows.length===0) return Buffer.from('', 'utf8');
const headers=Object.keys(rows[0]);
const cell=(value:unknown)=>{
let s=value==null?'':typeof value==='object'?JSON.stringify(value):String(value);
// Protect spreadsheet consumers from formula injection.
if(/^[=+\-@]/.test(s)) s=`'${s}`;
return `"${s.replace(/"/g,'""')}"`;
};
const lines=[headers.map(cell).join(',')];
for(const row of rows) lines.push(headers.map((h)=>cell(row[h])).join(','));
return Buffer.from(lines.join('\r\n'),'utf8');
}
private async xlsx(rows:Record<string,unknown>[]) {
const workbook=new ExcelJS.Workbook();
const sheet=workbook.addWorksheet('Export');
if(rows.length) {
const headers=Object.keys(rows[0]);
sheet.addRow(headers);
for(const row of rows) {
sheet.addRow(headers.map((h)=>{
const v=row[h];
if(v==null) return '';
if(typeof v==='object') return JSON.stringify(v);
let s=String(v);
if(/^[=+\-@]/.test(s)) s=`'${s}`;
return s;
}));
}
}
const result=await workbook.xlsx.writeBuffer();
return Buffer.from(result);
}
}

Architecture

High-level modules detected from the verified public snapshot. Protected implementation details are intentionally omitted.

appsmodule
.vscodemodule
.githubmodule

Technology stack

TypeScriptSQLMarkdownJSONGITIGNOREDOCKERIGNORENode.js / JavaScript ecosystem
TypeScript68.8%
SQL20.0%
Markdown10.9%
JSON0.3%
GITIGNORE0.1%
DOCKERIGNORE0.0%
CJS0.0%
MJS0.0%