This guide covers the development workflow, coding standards, and contribution guidelines for the Wallet Service.
git clone <repository-url>
cd wallet-service
npm install
cp example.env .env
# Edit .env with your development credentials
npm run dev
The server starts at http://localhost:3000 with hot-reload enabled.
| Command | Description |
|---|---|
npm run dev |
Start development server with hot-reload |
npm run build |
Build for production |
npm run start |
Start production server |
npm run test |
Run tests |
npm run lint |
Run linter |
npm run lint:fix |
Fix linting issues |
src/
├── index.ts # Entry point
├── server.ts # Server bootstrap
├── app/
│ ├── app.ts # Fastify application
│ ├── app.environment.ts # Environment config
│ ├── views/ # Template files
│ └── public/ # Static assets
└── lib/
├── controllers/ # Route handlers
├── services/ # Business logic
├── modules/ # Utility modules
├── jobs/ # Background tasks
├── util/ # Helper functions
├── assets/ # Static resources
└── certs/ # Certificates
any types; use unknown when type is uncertain// ✓ Good
async function getPass(serialNumber: string): Promise<Buffer> {
// ...
}
// ✗ Avoid
async function getPass(serialNumber): any {
// ...
}
The project uses XO for linting with custom rules:
Run the linter before committing:
npm run lint
This project follows Conventional Commits:
<type>[optional scope]: <description>
[optional body]
[optional footer]
Types:
| Type | Description |
|---|---|
feat |
New feature |
fix |
Bug fix |
docs |
Documentation only |
style |
Code style (formatting, etc.) |
refactor |
Code refactoring |
perf |
Performance improvement |
test |
Adding tests |
chore |
Maintenance tasks |
Examples:
# Feature
git commit -m "feat(apple): add push notification support"
# Bug fix
git commit -m "fix(auth): correct token validation regex"
# Breaking change
git commit -m "feat(api)!: change response format
BREAKING CHANGE: response now uses 'data' wrapper"
main - Production-ready codedevelop - Development branchfeature/* - Feature branchesfix/* - Bug fix branchesrelease/* - Release preparationControllers handle HTTP requests:
// src/lib/controllers/example.controller.ts
import { Controller, GET, POST } from 'fastify-decorators';
import type { FastifyRequest, FastifyReply } from 'fastify';
@Controller('/example')
export default class ExampleController {
@GET('/')
async list(request: FastifyRequest, reply: FastifyReply) {
return { items: [] };
}
@POST('/')
async create(request: FastifyRequest, reply: FastifyReply) {
// Handle creation
}
}
Services contain business logic:
// src/lib/services/example.service.ts
import { Service, Initializer } from '@fastify-decorators/simple-di';
@Service()
export class ExampleService {
@Initializer()
async init() {
// Initialize service
}
async doSomething(): Promise<void> {
// Business logic
}
}
Define schemas for request validation:
// src/lib/controllers/example.schema.ts
export const createSchema = {
body: {
type: 'object',
required: ['name'],
properties: {
name: { type: 'string' },
description: { type: 'string' }
}
},
response: {
200: {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' }
}
}
}
};
Member data is fetched from Salesforce via the salesforce.ts module:
import { getMemberData } from '../modules/salesforce';
const memberData = await getMemberData(salesforceId);
Generate passes using the apple.ts module:
import { createApplePass } from '../modules/apple';
const passBuffer = await createApplePass(memberData);
Generate save links using the google.ts module:
import { GoogleGeneric } from '../modules/google';
const saveUrl = await GoogleGeneric.createPass(memberData);
Set environment variables:
LOGGER=true
LOG_LEVEL=debug
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug Server",
"program": "${workspaceFolder}/src/index.ts",
"preLaunchTask": "npm: build",
"outFiles": ["${workspaceFolder}/build/**/*.js"]
}
]
}
Use the Swagger UI at /docs or tools like:
Ensure certificates are correctly placed in src/lib/certs/ and the passphrase is set in .env.
Verify Salesforce credentials and check if your IP is whitelisted.
Change the PORT in .env or stop the conflicting process:
lsof -i :3000
kill -9 <PID>