Skip to content
Alexandru Lungu
All work
Jun 2026 – present

Timber Logistic

Two-sided timber marketplace with a sealed-bid auction, card payments and Romanian e-invoicing

Timber Logistic home page: a forest aerial photo with the headline “Pădurea, mai aproape de tine” and marketplace call to action
Ledger
Live since
June 2026
Payments
live since Sep 2026 · Netopia cards · Oblio e-Factura invoicing
Supplier checks
ANAF company registry · SUMAL transport documents · manual approval
Database
20 tables · 45 migrations · RLS on every table
Edge functions
5 - payments, IPN, invoicing, notifications, registry lookup
Source
135 TypeScript files · ~20,000 lines · 158 commits
CI gate
schema rebuild in Postgres · SQL assertions · 88 unit tests · bundle secret scan · post-deploy check
Figures as of 2026-09-28
Context
Role
Sole developer - product, frontend, database, payments, infrastructure and compliance implementation
Client
Timber Logistic SRL, Timișoara
Stack
React 19TypeScriptSupabasePostgreSQLEdge FunctionsNetopiaOblioCloudflare Turnstile + DNSGitHub Actions

The auction is a database feature, not an application feature

When a buyer posts a request, each matching supplier gets exactly one hour of their own working time to bid - computed from that supplier's work_start, work_end and work_days, not a fixed 08–17 day. That deadline is snapshotted per supplier the moment the request is posted, so a supplier cannot extend their own window by editing their hours afterwards. The request's overall close is the latest of them.

All of this is triggers and a pg_cron job. The browser never computes a deadline it could get wrong, and there is no server process to be down. Requests that never reach a decision expire on their own.

The money path was reverse-engineered, gated, then launched

Netopia's v2 documentation was unavailable, so the API contract came from reading their published client package. The integration covers the start call, the IPN callback that is the only thing allowed to mark a payment paid, and Oblio invoicing behind it into Romania's e-Factura system - with a test invoice proving the VAT split to the cent.

Commission is a generated column with exact-decimal VAT arithmetic. Money never passes through a JavaScript float. The path stayed behind release switches in both the frontend and the backend until the merchant contract was signed, because an ungated buyer would otherwise have typed a real card into a sandbox form. It went live in September 2026.

The database is the security boundary

Row-level security on every table, every state change routed through SECURITY DEFINER procedures, no generic UPDATE policies at all, and Cloudflare Turnstile in front of registration so the supplier pipeline is not a bot target. A client bug can fail to show a buyer their own data; it cannot show them someone else's. Contact details unlock only for the winning pair, and only after the gateway's callback confirms the commission - never because the browser came back from a payment page.

The same posture reaches the pipeline: CI decodes every JWT it can find in the production bundle and fails the build if any of them is a service key. It has never fired, which is the point.

Delivery is a claim, not a verdict

A supplier marking an order delivered starts a window: the buyer confirms, disputes with evidence, or it auto-confirms after seven days. Only a confirmed delivery finalises the request and unlocks the review. A dispute resolved for the buyer opens a refund automatically. The platform also includes an EU DSA Article 16 notice-and-action system with an immutable audit trail, plus Romanian-language GDPR and ANPC compliance flows.

Supplier identity and delivery documents are verified in production. A supplier's CUI is checked in the browser, the Edge Function and the database, and legal identity comes from the ANAF registry, not from the supplier's form. A transport document code is verified against Romania's SUMAL register. The buyer's seven-day confirmation window starts only after verification passes. A registry outage or an issuer mismatch fails closed into manual review with an audit trail.