This repository started as a successful job application challenge implementation of a frontend for the Star Wars API (SWAPI) and has been evolved into a production-oriented (yet not fully production ready) Angular monorepo template optimized for responsive server-first rendering and ready for custom APIs and services.
Currently the SWAPI is down due to a expired TLS certificate, but data is mocked with an artificial request delay at the moment until I created my own backend.
-
The first request can take longer, as the fly.io machine will automatically suspend if there was no traffic for a while.
- Modern Angular architecture with standalone components, zoneless change detection, and lazy-loaded routes
- Hybrid rendering setup with CSR, SSR, and SSG in one codebase
- Device-aware server-first routing using Client Hints + URL device context parameters
- Strict environment/schema validation and shared typed contracts across packages
- Defensive third-party API integration for SWAPI with explicit DTO-to-model mapping
- Docker-ready build and runtime setup
| Package | Responsibility |
|---|---|
packages/client |
Angular app (browser + server entry, routes, pages, UI blocks/components) |
packages/server |
Hono host for security checks, device context handling, redirects, SSG file serving, SSR fallback |
packages/shared |
Shared runtime/types, routing constants, device context schema, code generators |
scripts |
Helper scripts for build/runtime tasks |
- Validate host/protocol (
SWAPI_ALLOWED_HOSTS, target-aware HTTP/HTTPS checks). - Read device context from Client Hints headers (
Sec-CH-UA-*, viewport hints). - Normalize URL to a device-context prefix segment like
r;format=mobile;width=768. - Serve static assets from the built browser output.
- Serve prerendered HTML (SSG) when a matching file exists.
- Fall back to Angular SSR for all non-prerendered HTML routes.
- Static prerendered paths are generated from
@swapi/shared/routing/ssg-paths. - Currently includes:
errorhomewith all generated device-context variants
- At the moment this results in
98prerendered routes in total.
- Routes:
home,movies,movie/:id,characters,character/:id,planets,planet/:id,error - SWAPI resources: Films, People, Planets
- HTTP retry interceptor and explicit SWAPI DTO/model mapping layer
- Responsive & a11y friendly UI
- The search input in the header is only UI demonstration, and has no functionality.
- DeviceService with route-aware and browser-aware breakpoint handling
- Clear client/server request behavior for stable, predictable runtime behavior.
- Automatic cancellation of obsolete in-flight requests during fast navigation to reduce unnecessary backend load.
- CDN-ready caching model with explicit cache headers and cache tagging support.
- Consistent HTTP error and timeout responses with cache-safe semantics.
- Isolated SSR execution in a worker pool with controlled concurrency and bounded queueing.
- Worker recovery and runtime metrics for observability and operational diagnostics.
- Graceful shutdown with in-flight request draining for safer deploys and restarts.
SWAPI is intentionally integrated defensively because of schema and data inconsistencies.
- See details in docs/swapi.md
- Includes known API behavior differences, mapping strategy, and fallback decisions
As of May 2026, the public swapi.dev API is unstable due to an expired TLS certificate.
To keep the app reliably usable across environments, the client currently serves SWAPI responses from local mock data.
- Mock source: SWAPI fixture data (
Juriy/swapi) transformed to SWAPI-compatiblefilms,people, andplanetsAPI responses - Activation:
SWAPI_USE_MOCK=truein client environment files - Mock transport behavior: includes an artificial per-request delay (
150-450ms) for both success and404responses
This is a temporary fallback until the app is switched to its own backend.
-
Node.js
Version: 24.14.1
It's recommended to have a node version manager compatible with .node-version set up for automatic installation and update of the Node.js version used in the project.
-
Bun
Version: 1.x
Only necessary to install the dependencies. The bun binary that is to be used for in the project will be installed via
package.jsonand is used throughout the tasks viabunx bunin order to align the bun version for every developer and with the production runtime environment (a fixed version of oven/bun docker image is used). -
Taskfile
It's recommended to install Taskfile on the system plus setting up shell completion.
Otherwise you could run:
bunx [--no-install] task -
Fly.io CLI
For deployment.
task i# Start `vite` dev server (only CSR, hot reload).
task client:dev
# ~ Build and start with `release` profile.
task client:start
# Start `bun` + `hono` server with SSG and SSR in dev mode.
# Notice: It's not yet fully direct code execution, no client hot reload.
task server:dev
# ~ Build and start with `release` profile.
task server:start
# ~ Add bundling.
task server:bundle
# ~ Build and run in Docker.
task docker:startLocal URLs:
- App's vite server in development mode:
http://localhost:4200 - App's vite server in production mode:
http://localhost:4300 - App's bun + hono Server in development mode:
http://localhost:50000 - App's bun + hono Server in production mode:
http://localhost:51000
task lint
task fixtask client:testUse PROFILE and TARGET explicitly when needed:
PROFILE:debugorreleaseTARGET:- server:
local,testing,production - client browser build also supports
pages
- server:
Taskfiles load environment values from checked-in .env files:
packages/client/.env/.env.<target>.<profile>packages/server/.env/.env.<target>.<profile>- Docker runtime variants additionally use
packages/server/.env/.env.<target>.<profile>.docker
Main runtime variables:
SWAPI_TARGET(local|testing|production)SWAPI_PROFILE(debug|release)SWAPI_RUN_MODE(source|build)SWAPI_USE_MOCK(true|false, client runtime flag for SWAPI mock responses)SWAPI_SERVER_PORTSWAPI_SERVER_HOSTSWAPI_ALLOWED_HOSTS
See the project roadmap documents in the docs/roadmap folder.