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:
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?

Dodaj komentarz