অধ্যায় ০.২ — সিস্টেম আর্কিটেকচার
১. উদ্দেশ্য
এই অধ্যায়ে travoBooks-এর উচ্চ-স্তরের আর্কিটেকচার ব্যাখ্যা করা হয়েছে — architectural pattern, tier-গুলো, logical service-গুলো, data flow নিয়ন্ত্রণকারী principles, এবং প্ল্যাটফর্ম যেসব failure mode থেকে বাঁচার জন্য ডিজাইন করা হয়েছে। অধ্যায় ০.৪ এই আর্কিটেকচার বাস্তবায়নকারী নির্দিষ্ট প্রযুক্তি পছন্দ কভার করে; এই অধ্যায় আর্কিটেকচার নিজেই ব্যাখ্যা করে।
২. Architectural Pattern — Service-Oriented Modular Architecture
travoBooks একটি service-oriented modular architecture হিসেবে নির্মিত: একাধিক পরিষ্কার-সীমানাযুক্ত Go service একটি common transactional data store শেয়ার করে, well-defined API-এর উপর যোগাযোগ করে, এবং স্বাধীনভাবে deploy ও scale হয়। এটি pure microservice mesh এবং single monolith-এর মধ্যে একটি deliberate position।
২.১ কেন pure microservices নয়
| Constraint | Implication |
|---|---|
| Booking issuance এবং journal entry posting একই database transaction-এ commit হতে হবে | আলাদা ledger service তার নিজস্ব database-সহ ledger-এর উপর eventual consistency চাপিয়ে দেবে — অগ্রহণযোগ্য |
| Financial integrity independent deployability-এর চেয়ে বেশি গুরুত্বপূর্ণ | Saga patterns এবং compensating transactions money flow-এ আমরা গ্রহণ করব না এমন ঝুঁকি যোগ করে |
| Service-সংখ্যার সাথে operational complexity বাড়ে | একটি ছোট focused engineering team-এর কয়েক ডজন স্বাধীনভাবে-deployed service maintain করা উচিত নয় |
২.২ কেন pure monolith নয়
| Constraint | Implication |
|---|---|
| Reporting workload booking latency-কে affect করতে পারবে না | Service-গুলো স্বাধীনভাবে scalable হতে হবে |
| Messaging-এ একটি failure booking-কে নামিয়ে আনতে পারবে না | প্রতি logical service-এর জন্য failure isolation প্রয়োজন |
| Frontend এবং backend team ভিন্ন cadence-এ ship করে | Independent deployment প্রয়োজন |
২.৩ আমরা যা পাই
- একটি ছোট সেট Go service, প্রতিটি একটি clear domain own করে
- একটি shared transactional database (MySQL Cloud Enterprise) — যাতে operation এবং ledger যখন প্রয়োজন তখন atomically commit হয়
- Common cache, queue, এবং coordination layer হিসেবে Redis
- প্রাথমিক client surface হিসেবে একটি React SPA
৩. চারটি Tier
┌──────────────────────────────────────────────────────────────────────┐
│ CLIENT TIER │
│ React.js SPA • Mobile Web • Partner Embedded UIs │
└─────────────────────────────────┬────────────────────────────────────┘
│ HTTPS · TLS 1.3 · REST · WebSocket
▼
┌──────────────────────────────────────────────────────────────────────┐
│ APPLICATION TIER (Go) │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ API Gateway │ │ Auth │ │ Booking │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Ledger │ │ Messaging │ │ Reporting │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ mTLS service-to-service · OpenTelemetry tracing │
└────────────┬──────────────────────────────────────────────┬──────────┘
│ TLS 1.3 TLS 1.3 │
▼ ▼
┌──────────────────────────┐ ┌──────────────────────────┐
│ DATA TIER │ │ CACHE & QUEUE TIER │
│ MySQL Cloud Enterprise │ │ Redis │
│ Primary + Read replicas │ │ Cluster + Sentinel │
│ Multi-AZ · PITR · TDE │ │ AOF persistence · ACL │
└──────────────────────────┘ └──────────────────────────┘
Tier-গুলোর মধ্যে প্রতিটি hop TLS 1.3 ব্যবহার করে। Go service-গুলোর মধ্যে inter-service traffic SPIFFE / Vault দ্বারা issued service identity সহ mTLS ব্যবহার করে।
৪. Logical Services
| Service | দায়িত্ব | প্রাথমিক Store |
|---|---|---|
| API Gateway | Request routing, authentication proxy, rate limiting, idempotency-key handling, request logging | Redis (rate buckets, idempotency keys) |
| Auth | Password, MFA, PAT, session management, RBAC enforcement | MySQL (users, roles, permissions); Redis (sessions) |
| Booking | Booking lifecycle, GDS/NDC orchestration, holds, issuance, voids, refunds | MySQL (bookings, tickets, segments); Redis (distributed locks, idempotency) |
| Ledger | Journal entries, account management, period state, reconciliation, recognition runs | MySQL (journals, accounts, periods) |
| Messaging | E-tickets, invoices, receipts, vouchers; email / SMS / in-app inbox / webhooks | Redis Streams (queue); MySQL (outbox, templates) |
| Reporting | Trial Balance, P&L, BS, CF, aging, deferred revenue roll-forward, audit packs | MySQL read replicas; Redis (computed report cache) |
| Integration | GDS / NDC clients, supplier adapters, BSP file ingestion | MySQL (supplier credentials, request log); Redis (response dedup) |
প্রতিটি service তার নিজস্ব table own করে। Cross-service read API-এর মাধ্যমে হয়, অন্য service-এর table-এ পৌঁছানোর মাধ্যমে নয়। Booking service একই transaction-এ booking write-এর সাথে সরাসরি JE writes সম্পাদন করে — এটিই একমাত্র cross-domain write pattern, এবং এটি বিদ্যমান কারণ financial integrity তা দাবি করে।
৫. মূল Architectural Decisions
৫.১ Transactional integrity — Booking ও Ledger একসাথে commit হয়
যেকোনো operational event যার একটি financial consequence আছে (ticket issued, payment captured, refund processed, memo accepted) একটি MySQL transaction open করে, operational rows লেখে, balanced JE lines লেখে, এবং atomically commit করে। যেকোনো অংশ ব্যর্থ হলে, সব অংশ roll back হয়। এটি প্ল্যাটফর্মের একক সবচেয়ে গুরুত্বপূর্ণ property।
Pattern-টি Go-তে sql.Tx ব্যবহার করে বাস্তবায়িত:
tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable})
// ... insert ticket
// ... update booking state
// ... insert JE header
// ... insert JE lines
err = tx.Commit()
৫.২ GDS call DB transaction-এর বাইরে হয়
External supplier call ধীর, hang করতে পারে, এবং অন্যথায় কয়েক দশ সেকেন্ড database lock ধরে রাখবে। প্ল্যাটফর্ম supplier_request_log row-এ intent record করে, সেটি commit করে, এবং তারপর একটি আলাদা Go goroutine-এ GDS call করে। শুধুমাত্র GDS response-এর পরে একটি দ্বিতীয় transaction ticket এবং JE post করে।
এই design-এর খরচ হলো "orphan tickets" (GDS সফল, আমাদের commit ব্যর্থ) সম্ভাবনা — যা একটি Reconciler service-এর দ্বারা handle করা হয় যা প্রতি পাঁচ মিনিটে চলে এবং supplier_request_log-কে booking_tickets-এর সাথে মিলায়।
৫.৩ Multi-tenancy by partition
প্রতিটি business-meaningful table partner_id বহন করে। প্রতিটি query partner_id-তে filter করে। Composite foreign keys (partner_id, *_id) ভিন্ন partner-এর rows reference করা physically impossible করে। Redis keys partner:{id}:... দিয়ে prefixed। S3 objects s3://travobooks-prod/partner-{id}/...-এর অধীনে থাকে।
৫.৪ Multi-currency at line level
প্রতিটি JE line transaction_currency, functional_currency, ঐচ্ছিক reporting_currency, এবং posting time-এ ব্যবহৃত snapshot FX rate বহন করে। Ledger কখনো historical postings retranslate করে না।
৫.৫ Double-entry by default
ব্যালেন্সড JE-এর মধ্য দিয়ে যায় না এমন financial state লেখার কোনো path নেই। ledger বাইপাস করে এমন কোনো "quick adjust" নেই। মোট debits মোট credits-এর সমান — সর্বদা।
৫.৬ Append-only financial state
journal_entries, journal_entry_lines, এবং audit_logs শুধুমাত্র INSERT accept করে। সংশোধন reversing JE-এর মাধ্যমে হয়। audit_logs-এ Hash chaining tampering detectable করে তোলে।
৫.৭ API-first
UI নিজেই public API-এর প্রথম consumer। Phase 1-এ কোনো internal-only endpoint বিদ্যমান নেই। React SPA যা করতে পারে, একটি partner integration তাও করতে পারে।
৫.৮ Stateless application tier
প্রতিটি Go service stateless — সব state MySQL বা Redis-এ থাকে। যেকোনো service instance যেকোনো request serve করতে পারে। Horizontal scaling purely additive।
৬. End-to-End Data Flow — Ticket Issuance
┌──────┐ 1. POST /v1/bookings/{id}/issue ┌────────────────┐
│React │ ───────────────────────────────────────▶│ API Gateway │
│ SPA │ │ (Go) │
└──────┘ └───────┬────────┘
│ 2. session lookup
▼
┌──────────┐
│ Redis │
└────┬─────┘
│ 3. authn ok, route
▼
┌────────────────┐
│ Booking │
│ Service (Go) │
└────┬───────────┘
4. acquire lock ◀────────┤
5. idempotency check
6. write "pending" row, commit
│
7. GDS call (goroutine, outside TX)
▼
┌──────────┐
│ GDS │
└────┬─────┘
│ 8. ticket number
▼
9. open TX, INSERT ticket + JE lines,
UPDATE booking → ISSUED, COMMIT
│
10. publish booking.issued event
▼
┌──────────────────┐
│ Redis Streams │
└────┬─────────────┘
│ 11. consume
▼
┌──────────────────┐
│ Messaging worker │
└────┬─────────────┘
│ 12. e-ticket → SES
▼
👤 Customer
এই একক flow প্রতিটি tier এবং প্রতিটি architectural principle exercise করে: stateless services, distributed locks, idempotency, GDS-outside-transaction, atomic ledger commit, Redis Streams-এর মাধ্যমে async messaging।
৭. Failure Mode এবং Resilience
| Failure | Detection | Recovery |
|---|---|---|
| GDS timeout | Go context deadline exceeded | একই idempotency key দিয়ে client retry; reconciler orphan ধরে |
| GDS সফল, আমাদের commit ব্যর্থ | supplier_request_log এবং booking_tickets-এর মধ্যে reconciler diff |
Audit trail সহ ops manually resolve করে; ticket row inserted, JE posted, alert raised |
| MySQL primary failure | Cloud-provider probe-এর মাধ্যমে health check | Multi-AZ failover < 60s; in-flight transactions client দ্বারা retried |
| Redis primary failure | Sentinel detect করে | Replica-তে automatic failover; brief read-only window |
| Whole-region outage | External synthetic monitoring | Phase 1: standby region-এ manual failover; Phase 2: active-active |
| Webhook consumer down (partner side) | Delivery attempt ব্যর্থ | Streams-এ exponential backoff; max 8 attempts; dead-letter |
| Background worker crash | Streams consumer group ACK দেখে না | Message pending list-এ ফেরে; অন্য consumer pick up করে |
| Bad deployment | Canary metrics regress | Deployment pipeline-এর মাধ্যমে automatic rollback |
৮. Deployment Topology
৮.১ Phase 1 — Single primary region, multi-AZ
- একটি primary region (যেমন বাংলাদেশ/ভারত partners-এর জন্য AWS Singapore; EU-এর জন্য AWS Frankfurt)
- তিনটি availability zone
- MySQL Cloud Enterprise: primary + 2 multi-AZ standby + read replicas
- Redis Cluster: AZ জুড়ে spread 6 node
- Go services: Kubernetes-এ deployed, pod anti-affinity rules-এর মাধ্যমে AZ জুড়ে spread replicas
৮.২ Phase 1 disaster recovery
- Continuous backup restore সহ standby region
- RTO target: 2 ঘণ্টা
- RPO target: < 5 মিনিট (PITR + Redis AOF)
৮.৩ Phase 2 — Active-active multi-region (roadmap)
- দুই বা ততোধিক active region
- Partner-pinned routing (প্রতিটি partner-এর reads তাদের nearest region-এ land করে)
- MySQL Group Replication বা Vitess-এর মাধ্যমে cross-region replication
- RTO target: < 60 সেকেন্ড
- RPO target: ~0
৯. Observability
প্রতিটি Go service emit করে:
- Structured JSON logs
partner_id,request_id,event_idcorrelation সহ - Prometheus metrics: প্রতি endpoint RED (Rate, Errors, Duration); প্রতি node USE (Utilisation, Saturation, Errors)
- OpenTelemetry traces: প্রতিটি request একটি trace ID বহন করে যা outbound GDS call সহ সব hop জুড়ে propagated
- Health probes:
/healthz(liveness) এবং/readyz(readiness, DB এবং Redis connectivity check)
Audit logs একটি আলাদা, tamper-evident stream — অধ্যায় ৮.২ দেখুন।
১০. Security Architecture (সংক্ষেপে)
সম্পূর্ণ আলোচনা অধ্যায় ১২.৫ (Data Protection) এবং অধ্যায় ০.৪ §১০-এ আছে। Architectural level-এ:
- প্রতিটি hop-এর মধ্যে TLS 1.3
- প্রতিটি Go service-এর মধ্যে mTLS
- HashiCorp Vault / AWS Secrets Manager-এ secrets — কখনো code বা logs-এ নয়
- At rest MySQL TDE; disk encryption সহ Redis; SSE-KMS সহ S3
- Append-only hash-chained
audit_logs - Sensitive operation-এর জন্য maker-checker প্রয়োজন
১১. Architectural Principles — সংক্ষিপ্তসার
- Booking + ledger একসাথে commit হয়। সর্বদা।
- GDS call database transaction-এর বাইরে হয়। Reconciler orphan handle করে।
- Multi-tenancy তিনটি layer-এ enforced হয়: application, database, storage।
- Financial state append-only। Reversal, কখনো update নয়।
- প্রতিটি service stateless। State MySQL বা Redis-এ থাকে।
- UI প্রথম API consumer। কোনো internal-only endpoint নেই।
- এক service-এর failure cascade হয় না। Redis-backed queue এবং timeout-এর মাধ্যমে bulkhead।
- প্রতিটি পরিবর্তন traceable। Hash chaining সহ audit logs।
এই principles, একসাথে নেওয়া, যা travoBooks-কে scale-এ enterprise-grade global travel accounting-এর জন্য উপযুক্ত করে।