A template Angular 20 project with Material UI, Tailwind CSS, Signals, i18n, ESLint, Prettier, Husky, and CI/CD.
Designed to kickstart new apps with a clean architecture and ready-to-go developer experience.
🚀 Angular 20 + standalone APIs + Angular Material
🎨 Tailwind CSS with Prettier-powered class sorting
🧠 Signals + Signal Store for reactive state management
🌐 ngx-translate with runtime /assets/settings.json
📜 Toast & Storage Services with smart fallback logic
🧰 ESLint, Prettier, Husky for consistent commits
🗂️ Ready-to-use VS Code workspace
🐳 GitHub Actions & Docker for CI/CD and release pipelines
- Run
npm ci. - Start the dev server with
npm startand openhttp://localhost:4200. - Walk through CHECKLIST.md to align tooling, runtime configuration, and CI.
- Review ARCHITECTURE.md for the folder structure and conventions.
-
ConfigServiceLoads/assets/settings.jsonduring bootstrap through anAPP_INITIALIZER, exposes the values via theAPP_CONFIGinjection token, and provides helpers likestorageKey('suffix')that respect the configured namespace. -
ThemeServiceProvides light/dark themes, system preference detection, and persists the last choice. It is initialized throughprovideAppInitializerinmain.ts, so the theme is ready before the first paint.this.themeService.toggleTheme(); this.themeService.setTheme('dark'); this.themeService.useSystemPreference();
-
StorageServiceWrapper aroundlocalStorageandsessionStoragewith JSON serialization, graceful fallback when storage is blocked, and helpers for scoped clearing.this.storage.setLocal('auth-user', user); const profile = this.storage.getLocal<User>('auth-user'); this.storage.clearSession();
-
LanguageServiceBootstraps the active language based on the browser locale and keepsdocument.documentElement.langin sync. Extend translations undersrc/assets/i18n. -
ToastServiceSimplifies translated toast notifications. Provide translation keys and optional interpolation params.this.toast.showSuccess('demo.fetch.success', { count }); this.toast.showError('demo.fetch.error');
-
SpinnerServiceprovides a global loading overlay driven by signals. Callshow()/hide()directly or wrap async flows withtrackObservable/trackPromiseto keep UX consistent.
- Theme styles live in
src/styles/themes/light.scssanddark.scss. Extend design tokens or CSS variables there. Both files target[data-theme="<name>"]so additions work for light and dark variants. - Global base styles are gathered in
src/styles/styles.scss. Tailwind utilities are available throughtailwind.css. - When adding a new theme name, update
ThemeService.availableThemesand create a matching stylesheet.
- Application level providers, interceptors, and config live under
src/app/core. - Shared UI building blocks are under
src/app/sharedand should stay framework agnostic (no feature-specific logic). - Feature modules sit in
src/app/features/<feature-name>and can be lazy loaded or standalone. Thedemofeature shows API fetching, toast usage, theme reactions, and storage helpers working together.
Runtime settings are loaded at startup from /assets/settings.json (copied from src/assets/settings.json during build). ConfigService merges the JSON with sane defaults and normalizes values such as the storage namespace.
{
"app": {
"name": "Demo Playground",
"storageNamespace": "demo"
}
}- Access configuration anywhere by injecting the
APP_CONFIGtoken or theConfigService. - Use
configService.storageKey('suffix')to build namespaced keys that match the runtime namespace. - Override settings in containerized deployments by providing environment variables (see the Docker section) or mount a custom
settings.json.
The repository ships a multi-stage Dockerfile (node:20-alpine -> nginx:alpine) that builds the Angular app and serves it through Nginx. At container start the entrypoint script rewrites /usr/share/nginx/html/assets/settings.json from environment variables so you can build once, run anywhere.
| Variable | Default | Description |
|---|---|---|
APP_NAME |
Demo Playground |
Display name exposed via ConfigService.appConfig.name. |
APP_STORAGE_NAMESPACE |
demo |
Prefix used for storage keys. Normalized (trimmed & trailing dot removed). |
CONFIG_PATH |
/usr/share/nginx/html/assets/settings.json |
Override only if the app is hosted from a different root. |
# Build image
DOCKER_BUILDKIT=1 docker build -t your-org/ng-ultimate-base:local .
# Run container with custom runtime config
docker run --rm -p 8080:80 \
-e APP_NAME="My Awesome App" \
-e APP_STORAGE_NAMESPACE="myapp" \
your-org/ng-ultimate-base:localservices:
ng-ultimate-base:
image: your-org/ng-ultimate-base:latest
ports:
- '8080:80'
environment:
APP_NAME: 'Compose Demo'
APP_STORAGE_NAMESPACE: 'compose'The release GitHub Action can optionally build and push the Docker image after the Angular build. Toggle the Build and push Docker image prompt (publish_docker) when you dispatch the workflow. Configure the following repository secrets before triggering a release if you plan to publish the container:
DOCKERHUB_USERNAME– Docker Hub account used for pushes.DOCKERHUB_TOKEN– Access token or password for that account.DOCKERHUB_REPOSITORY– Target repository inuser/imageformat (e.g.acme/ng-ultimate-base).
Tags published when enabled:
user/image:X.Y.Z(from the workflow input)user/image:latest
If the Docker option is left unchecked the workflow skips container publishing and still produces the ZIP artifact and GitHub Release. When the option is enabled the workflow requires the Docker Hub secrets and aborts the release if building/pushing the image fails.
- Replace the demo feature with your domain feature set and keep the same folder conventions.
- Tailor
src/assets/settings.json(or runtime env vars) with your product name, storage namespace, and other config values. - Harden CI by adding test coverage thresholds or integration tests that reflect your stack.
- Extend the release workflow if you need to publish to additional targets (e.g. Firebase Hosting, Vercel).
- Add more languages by dropping new JSON files into
assets/i18nand extending the language selector UI.
- Keep shared services stateless where possible; prefer Signal Stores inside features for business data.
- Use
ConfigService.storageKey()for any persisted state so runtime namespaces stay in sync. - Call
ThemeService.toggleTheme()from UI controls instead of manipulating classes manually. - Group Tailwind utility classes logically; Prettier with the Tailwind plugin keeps them sorted for you.
- Treat
developas the integration branch and protect it with required status checks provided by the existing GitHub Actions workflows. - For quick pimp-up code you can use
npx prettier --write .andng lint --fixin root folder to automatic format code and fix minor eslint problems in all files.
- CHANGELOG.md - release history.
- ARCHITECTURE.md - folder layout, layers, and extension guidance.
- CHECKLIST.md - one-time setup steps after cloning.
.github/workflows/- CI/CD definitions for pull requests, releases, and Docker pushes.
