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

- 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
- 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.
Multi-tenant digital menu builder with AI menu import - design a menu, publish it as a link or QR code