Thuý Nga Wedding & Event
End-to-end delivery of a production platform for a wedding and event decoration business in Hanoi: a public Vietnamese website plus an internal CMS and CRM that follows each deal from first enquiry to a completed event.
Milestones M0–M11 delivered between September and October 2026, with public go-live on 22 October 2026.
Production source code is private; the showcase repository is a documentation-only case study.
Overview
I delivered this platform end to end for a real client: product scope, architecture, backend and frontend implementation, security, testing, deployment, and go-live, starting from an empty repository and ending in a public production release.
My Role
Sole engineer, from requirements and architecture through implementation, testing, deployment, and go-live.
Product Scope
Public website and CMS, lead CRM, customers, events, appointments, quotations with PDF, and payment tracking.
Delivery
A foundation milestone and eleven delivery milestones, ending with security hardening, staging and user acceptance testing, business acceptance, and go-live.
How this complements H2ALL / FastLink
H2ALL / FastLink shows assigned work inside a large enterprise platform. Thuý Nga shows full ownership of a smaller system: scope, architecture, security, testing, deployment, and production delivery.
Project Objectives
- Present the business's services and completed work in a fast, mobile-first Vietnamese website the business can maintain itself.
- Capture quote and consultation requests safely and route them into one admin workflow.
- Follow every deal from lead to customer, event, appointments, quotation, and payments, with an audit trail.
- Go live with a system that is secure by default, tested end to end, and operable by a very small team.
Business Capabilities
Public Website & CMS
Services, completed projects with photo albums, guides, testimonials with recorded consent, contact, privacy policy, and SEO with structured data. Services, projects, guides, testimonials, and site content are managed from the CMS.
Lead CRM
Quote and consultation requests land in one inbox with a status workflow, an append-only activity timeline, duplicate-phone warnings, and notifications.
Customers, Events & Appointments
Explicit lead-to-customer conversion, an event lifecycle, consultations and site surveys, and a month calendar of scheduled work.
Quotations & PDF
Line items, discount, and an optional required deposit, with yearly numbering, a status workflow, and an on-demand PDF with Vietnamese typography.
Payment Tracking
Records payments already received against an accepted quotation. The remaining balance is always derived, never stored.
Administration & Audit
System and business admin roles, authenticator-app two-factor authentication, account management, and an audit log.
Deliberately out of scope: online payments, invoicing and accounting, a customer portal, and messages to customers.
Architecture
A modular monolith: one ASP.NET Core API split into Api, Core, and Infrastructure projects with a strict dependency direction, and a Next.js application serving both the public website and the admin UI. The API is served on the same origin as the web app, and notification e-mail flows through a transactional outbox.
HTTP host, controllers, authentication, and authorization
Domain models and business rules, with no project dependencies
EF Core persistence, media, PDF, bot protection, and e-mail
Technology Stack
Backend
Frontend
Data & Services
Quality & Delivery
Backend Engineering Highlights
Correct Workflows Under Concurrency
Exactly-once lead conversion with a race-safe duplicate check, idempotent public submissions, and version checks on quotations and payments.
Money Rules on the Server
Totals, discounts, and deposits in whole đồng; payments only against an accepted quotation and never beyond its total.
Append-only History
Lead activity timelines, cancel-and-re-record payments, and an audit log with sanitized metadata.
Reliable Notifications
E-mails staged in the same transaction and delivered in the background, at least once, carrying no customer data.
Documents and Media
On-demand quotation PDFs with embedded Vietnamese fonts; public media stored without embedded metadata.
Safe Test Infrastructure
A generated database per test run behind a guard that fails closed before touching any other database.
Decisions & Trade-offs
Modular monolith, not microservices
Why: One business, related workflows, and transactions that span modules.
Trade-off: No per-module scaling; clear Api / Core / Infrastructure boundaries keep a later split possible.
Same-origin cookie authentication
Why: HttpOnly cookies, antiforgery tokens, and no cross-origin access to configure.
Trade-off: Clients must handle antiforgery tokens, and the reverse proxy must route the API path.
Server-side money, derived balances
Why: Whole-đồng amounts computed by the server; balances calculated on read, so they cannot drift.
Trade-off: A small amount of computation on every read.
Append-only payments
Why: Payments are cancelled and re-recorded instead of edited or deleted, keeping a complete history.
Trade-off: Corrections take two steps.
Transactional outbox, no broker
Why: Notification e-mails are staged with the request and delivered in the background without operating a broker.
Trade-off: At-least-once delivery; a stable message identifier mitigates duplicates.
Fail-closed configuration
Why: Outside development the API refuses to start with development switches or missing settings, and the web app refuses to build without its required settings.
Trade-off: Stricter, more explicit deployments.
Security & Reliability
Security & Privacy
- Authenticator-app two-factor authentication, mandatory for the system administrator
- Deny-by-default authorization, verified by an automated sweep of every endpoint
- Antiforgery tokens, bot protection on public forms, and rate limiting
- Content-Security-Policy with a per-request nonce and a stricter admin policy
- Private images streamed only to signed-in administrators
- Consent-gated analytics (off at launch), click-to-load video, and a privacy policy
Reliability & Delivery
- Idempotent public submissions and version checks on quotations and payments
- CI check that database migrations match the model
- Pinned toolchain, locked restores, and NuGet / npm vulnerability audits
- Migration and backup/restore procedures rehearsed before go-live
- Staging with user acceptance testing and a protected production preview
- Releases identified by exact commit, with the previous release kept for rollback
Testing & CI/CD
265 Backend test-project files
96 unit and 169 integration C# files, including shared test infrastructure
~1,950 xUnit test methods
Facts and theories; theories run several cases
57 Frontend unit-test files
Run with the Node.js test runner
60 Playwright specs
Desktop 1440 px and phone 375 / 360 px journeys
Test inventory at the production release: counts of test files and test methods, not executions.
- Step 1
Locked restore, build, migration check, and vulnerability audit
- Step 2
Unit and integration tests on a throwaway SQL Server
- Step 3
Lint, typecheck, unit tests, and production build
- Step 4
Playwright journeys against the real API
- Step 5
Merge only on green CI for the exact commit
GitHub Actions runs on every pull request, with actions pinned to full commit SHAs and a read-only token. CI stores no secrets and performs no deployment; releasing is a separate, approved step.
Delivery & Milestones
- M0Platform foundation and technical spikes
- M1Authentication, 2FA, and admin shell
- M2Services and basic CMS
- M3Portfolio and media
- M4Public website and SEO foundations
- M5Quote requests and lead CRM
- M6Customers, events, appointments, and calendar
- M7Quotations, pricing, and PDF
- M8Payment tracking and remaining balance
- M9Notifications, e-mail, and SEO completion
- M10Security hardening, staging, and UAT
- M11Production readiness and go-live
Path to production
Security hardening, then a production-like staging environment with user acceptance testing, business acceptance by the client, and a protected preview of the production site. The public go-live followed on 22 October 2026, and a Next.js security update shipped to production the next day.
Lessons Learned
- Out-of-scope lists matter as much as scope: writing down what each milestone would not do (for example, no payment gateway) kept delivery focused.
- An application that refuses to start without its required settings turns a configuration checklist into an automated gate.
- Concurrency, idempotency, and money rules are best proven against a real database rather than mocks.
- Privacy work needs lead time: consent, data-protection procedures, and the privacy policy had to be ready before launch.
- Development was supported by Claude Code, with independent AI-assisted technical reviews. Project decisions, manual QA, release approvals, and final acceptance remained under human ownership.