This application uses a client - server architecture.
The client stack is:
- Vite
- React
- Tanstack Router
- Better-Auth
- Tanstack Query (upcoming)
- TailwindCSS (upcoming)
- Shadcn UI (upcoming)
The server stack is:
- Bun
- Hono
- PostgreSQL
- Prisma
- Better-Auth
- Zod (upcoming)
- Navigate to the server directory and run
bun installto install the dependencies. - Create the
.envfile and add the environment variables from the.env.examplefile.
BETTER_AUTH_SECRET=
BETTER_AUTH_URL=
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
DATABASE_URL=
- Run
bun run devto start the development server.
- Navigate to the client directory and run
bun installto install the dependencies. - Run
bun run devto start the development server.
The server uses Redis to cache OCR inference results, reducing cost and latency for repeated or duplicate requests. This is especially important for SaaS scalability and high request volumes.
- Cache Key: SHA-256 hash of the image data, namespaced by OCR type (e.g.,
car-plate:<hash>) - Default TTL: 7 days (configurable via environment variable)
- Backend: Redis (local or managed, e.g., AWS ElastiCache)
Add the following to your .env file:
REDIS_URL=redis://localhost:6379
CACHE_TTL_SECONDS=604800 # 7 days
You can run Redis locally using Docker:
docker run -d -p 6379:6379 --name redis redis
The server uses a custom logger middleware for all HTTP requests, outputting structured JSON logs. This includes:
timestamp: ISO string of the request timerequestId: Unique request ID (via hono/request-id)method: HTTP methodpath: Request pathstatus: HTTP status codeserverTiming: Value of theServer-Timingresponse header (set by hono/timing)cacheStatus: Indicates if the result was served from cache (hit,miss, ornone)
Metrics:
- The
Server-Timingresponse header is set using hono/timing, which can be used by clients and observability tools to measure response times.
Example log:
{
"timestamp": "2024-05-20T12:34:56.789Z",
"requestId": "b7e1c2f0-1234-4a5b-8c2d-abcdef123456",
"method": "POST",
"path": "/api/ocr/car-plate",
"status": 200,
"serverTiming": "total;dur=123",
"cacheStatus": "hit"
}