Commit graph

25 commits

Author SHA1 Message Date
0dc31fbafe
storage: S3 client wrapper and admin Basic-auth middleware
S3 module wraps aws-sdk-s3 against MinIO. Two clients on purpose:

- The bytes-mover client points at S3_ENDPOINT (internal minio:9000 over
  the storage Docker network).
- The presign-only client points at S3_PUBLIC_ENDPOINT (https://s3.asxp.io
  via Traefik) so the URLs it mints resolve from a browser.

force_path_style on both because subdomain-style URLs would require wildcard
DNS under s3.asxp.io.

AdminAuth is a tiny Rack middleware that 401s any request under /admin
unless HTTP Basic credentials match ADMIN_USER / ADMIN_PASSWORD from env.
Fails closed if either env var is missing.
2026-05-26 17:43:48 +03:00
a605ccdc52
invoicing: Prawn PDF renderer with Noto fonts
InvoicePdf.render(invoice) returns A4 PDF bytes. Layout: title + number,
horizontal rule, two-column FROM/BILL TO, meta strip (issued/due/currency/
status) bracketed by rules, line items table, right-aligned totals with
optional GEL equivalent, payment block (Bank of Georgia IBAN), optional
notes, repeating footer with issuer ID and page number.

Both party columns capture pdf.y after rendering and the global cursor jumps
to whichever ran longer — avoids the bbox cursor-restore footgun that was
collapsing the meta strip into the FROM column.

Noto Sans Georgian is registered as a fallback family so the Georgian legal
name renders without needing a separate text run.

Issuer details (legal name, tax ID, registration, address, bank) are
hardcoded as a constant — these are public on the rendered site already and
change rarely enough that a config file would be overkill.
2026-05-26 17:43:38 +03:00
1220f37d5f
invoicing: Invoice model with number allocation and totals
Sequel::Model wrapper over the invoices table. Three responsibilities:

- Invoice.build takes form params (client, currency, GEL rate, items array)
  and returns an unsaved Invoice with a freshly-allocated number, normalized
  line items, and computed subtotal.
- Invoice.allocate_number scans for the highest INV-<year>-NNNN and
  increments. Single-process deploy means no contention; if that changes
  this needs a DB-side sequence per year.
- Instance methods: paid?, status, total, total_gel for the PDF renderer
  and the public landing page.

Items are stored as JSONB; qty and unit_price are kept as strings on the
way in/out so BigDecimal arithmetic stays exact through the JSON round-trip.
2026-05-26 17:43:28 +03:00
3fdb0f36b3
db: connection helper and invoices migration
DB.connect! opens a single Sequel connection from DATABASE_URL; DB.migrate!
runs Sequel migrations from db/migrations/.

The first migration creates the invoices table: uuid PK, unique invoice
number, client + currency fields, JSONB for line items, GEL conversion rate
captured at issue time, paid_at for the status toggle, pdf_key for the
MinIO object.
2026-05-26 17:43:18 +03:00
bf4683a973
fonts: vendor Noto Sans + Noto Sans Georgian
Prawn needs explicit TTFs to render anything beyond the built-in Latin
glyphs. Bundling Noto Sans (Latin/Cyrillic) and Noto Sans Georgian lets the
invoice PDF show both Latin and Georgian forms of the legal name.

OFL.txt is the upstream SIL Open Font License covering all five files.
2026-05-26 17:29:30 +03:00
2ea46b12e6
gems: add pg, sequel, prawn, aws-sdk-s3 for invoicing
- pg + sequel: connect to the storage stack's Postgres.
- prawn + prawn-table: render invoice PDFs.
- aws-sdk-s3: upload PDFs to MinIO and mint presigned download URLs.

Also pulls libpq-dev into the Docker build (for the pg gem) and the
postgresql client lib into the Nix dev shell.
2026-05-26 17:29:21 +03:00
1e4bded4ae
compose: join external storage network
The new asxpio/storage stack owns a Docker network named "storage" carrying
Postgres and MinIO. The app joins it (alongside traefik) so it can reach
postgres:5432 and minio:9000 by service name.
2026-05-26 17:29:09 +03:00
c3f37e6cb0
more SEO: org -> person
All checks were successful
Build and Deploy to Production / build (push) Successful in 47s
Build and Deploy to Production / deploy (push) Successful in 32s
2026-05-05 01:45:18 +04:00
7296ffc944
SEO optimization
All checks were successful
Build and Deploy to Production / build (push) Successful in 45s
Build and Deploy to Production / deploy (push) Successful in 32s
2026-05-05 01:13:59 +04:00
7608cf15fc
useful icon and links
All checks were successful
Build and Deploy to Production / build (push) Successful in 45s
Build and Deploy to Production / deploy (push) Successful in 32s
2026-05-05 00:57:11 +04:00
1ab09043ee
ruby rework with contact form
All checks were successful
Build and Deploy to Production / build (push) Successful in 51s
Build and Deploy to Production / deploy (push) Successful in 34s
2026-05-05 00:45:27 +04:00
90402ae14a
ie sergei poljanski georgia
All checks were successful
Build and Deploy to Production / build (push) Successful in 16s
Build and Deploy to Production / deploy (push) Successful in 40s
2026-05-05 00:02:26 +04:00
0cc457c1fa
hedgehog
All checks were successful
Build and Deploy to Production / build (push) Successful in 6s
Build and Deploy to Production / deploy (push) Successful in 19s
2025-11-25 05:27:31 +02:00
9071cad3e5 Merge pull request 'ci/cd' (#1) from fix/pipeline into main
Some checks failed
Build and Deploy to Production / build (push) Failing after 7s
Build and Deploy to Production / deploy (push) Has been skipped
Reviewed-on: https://git.asxp.io/asxpi/asxpio/pulls/1
2025-11-25 03:25:25 +00:00
13f6db18f2
ci/cd 2025-11-25 05:24:04 +02:00
20123ffa98
quality of life changes, removed old icon 2024-04-13 23:35:44 +03:00
31edd556c6
SSH and PGP keys added, changed icon 2024-04-13 22:32:32 +03:00
8a4f8449a8
Added links v4 2023-08-25 05:11:15 +03:00
734b339701
Added links v3 2023-08-25 05:08:17 +03:00
6c2dc72ddc
Added links v2 2023-08-25 05:05:00 +03:00
11f354b6d0
Added links 2023-08-25 05:00:34 +03:00
0f250c84ed
Added site icon 2023-08-21 04:14:42 +03:00
4584843b70 font for footer 2023-08-03 00:33:39 +03:00
50a86b0a83 Chaned font 2023-08-02 20:33:42 +00:00
3d3bf93100 initial commit 2023-08-02 20:02:39 +00:00