Day#15 Account Registration, Subscription Plans, Email Verification & i18n

Today I focused on finalizing account registration RESTful webservice, subscription logic, implementing account verification, and introducing language support. It was a day of careful structuring, breaking cyclic dependencies, and refining developer UX. Here’s what got done:

mariusz
mariusz
20 posts
2 followers

Subscription Models

  • Created `SubscriptionPlan` and `Subscription` entities.
  • `Subscription` includes plan metadata copied at creation:
  • `planName`, `price`, `currency`, `billingCycle`
  • Refactored TypeORM relations:
  • Removed cyclic `@OneToMany` from `SubscriptionPlan`
  • Used string-based `@ManyToOne(’SubscriptionPlan’)` to avoid early reference issues

Enums

  • `BillingCycle`: `monthly`, `yearly` (used both in TypeScript and PostgreSQL enum)
  • `SubscriptionStatus` corrected to match PostgreSQL enum format:
  • values are lowercase in DB: `active`, `cancelled`, `paused`

Seed Data

  • Seeded a `trial` plan in `subscription_plans` table:
  • `subscriberId`: from admin user
  • `price`: `0.00`
  • `currency`: `PLN`
  • `billingCycle`: `monthly`
  • `active`: `true`

User Registration

  • Method `register()` in `AuthService`:
  • Verifies email uniqueness
  • Creates partner with `active: false`
  • Generates JWT (10 min expiration)
  • Builds email verification URL (uses frontend env)
  • Sends activation link via email or logs to console if SMTP unavailable

Email Verification

  • REST service Endpoint: `POST /auth/verify-email`
  • Method `verifyEmail(token)` in `AuthService`:
  • Validates JWT with secret and expiry
  • Sets `active = true` on user
  • Creates trial subscription after activation
  • Handles expired or invalid tokens with localized errors

i18n Support

  • Dropped `nestjs-i18n` (too many type issues)
  • Implemented custom `TranslationService`:
  • Loads JSON files from `/i18n/[lang]/auth.json`
  • Interpolates variables like `{{firstName}}`, `{{url}}`, `{{expires}}`
  • Language detected from `x-lang` HTTP header

Email Delivery

  • Function `sendMail(…)`:
  • Fetches subject and body via `translationService.t(lang, key, args)`
  • Formats message per language (HTML/plaintext)
  • SMTP errors (e.g., `535 Authentication failed`) are caught and logged

Translation File Structure

„`
/apps/partner/api/i18n
/pl/auth.json
/en/auth.json
„`


`.env` Configuration

„`
JWT_VERIFY_EMAIL_SECRET=verify-email-secret
JWT_VERIFY_EMAIL_EXPIRES_IN=10m
FRONTEND_URL_LOCAL=http://localhost:3000
FRONTEND_URL_PUBLIC=https://frontend.tyolabs.com

SMTP_HOST=smtp.tyolabs.com
SMTP_PORT=465
SMTP_SECURE=true
SMTP_USER=no-reply@tyolabs.com
SMTP_PASS=…
„`


Test Scenarios

  • Register → receive activation email
  • Click activation link → account activated
  • Re-register same email → `409 Conflict` with localized message
  • Login attempt without activation → `401 Unauthorized`
  • Test language detection via `x-lang: pl` and `x-lang: en`

Everything now works — enum handling, subscriptions, email flows, language switching, and error reporting. Tomorrow: dashboard logic and self-service plan upgrades?


Opublikowano

w

,

przez

Komentarze

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *