|
1 | 1 | <p align="center"> |
2 | | -<a href="https://github.com/codebar-ag/laravel-template.git" target="_blank"> |
3 | | -<img src="https://banners.beyondco.de/Laravel%20Template.png?theme=dark&pattern=architect&style=style_1&description=codebar+Solutions+AG&md=1&showWatermark=0&fontSize=100px&images=https%3A%2F%2Flaravel.com%2Fimg%2Flogomark.min.svg" alt="Laravel Logo"> |
4 | | -</a> |
| 2 | + <img src="public/images/logos/codebar-logo-colored.svg" alt="codebar Solutions AG" width="260"> |
5 | 3 | </p> |
6 | 4 |
|
7 | | -## About Laravel Template |
| 5 | +<h1 align="center">www.codebar.ch</h1> |
8 | 6 |
|
9 | | -Laravel Template is a project template for all Codebar Solutions AG Laravel applications. |
10 | | -It is a starting point for new Laravel projects. |
11 | | -It includes a basic setup for a Laravel application with some common packages and configurations.: |
12 | | - |
13 | | -- Auth |
14 | | -- Support for Microsoft Office 365 Authentication |
15 | | -- Enums |
16 | | -- [Laravel Nova](https://nova.laravel.com). |
17 | | -- [Flysystem Cloudinary](https://github.com/codebar-ag/laravel-flysystem-cloudinary). |
18 | | -- [Flysystem Cloudinary Nova](https://github.com/codebar-ag/laravel-flysystem-cloudinary-nova). |
19 | | -- [Spatie Activity Log](https://github.com/spatie/laravel-activitylog). |
20 | | -- [Spatie Health](https://github.com/spatie/laravel-health). |
21 | | -- [Spatie Permission](https://github.com/spatie/laravel-permission). |
22 | | - |
23 | | -## Installation |
24 | | - |
25 | | -You can use this template by clicking on the `Use this template` button on the top of this github repository page. |
26 | | - |
27 | | -**INSERT IMAGE HERE* * |
28 | | - |
29 | | -Once you have created a new repository from this template, you can clone it to your local machine and install the dependencies: |
30 | | - |
31 | | -```bash |
32 | | -composer install |
33 | | - |
34 | | -cp .env.example .env |
35 | | -cp vite.config-example.js vite.config.js |
36 | | - |
37 | | -php artisan key:generate |
| 7 | +<p align="center"> |
| 8 | + The public marketing website of <a href="https://www.codebar.ch">codebar Solutions AG</a> — a small software company based in the Basel region, Switzerland. Laravel, Blade and Tailwind, bilingual (DE/EN), content managed as version-controlled files rather than through an admin panel. |
| 9 | +</p> |
38 | 10 |
|
39 | | -php artisan migrate --seed |
| 11 | +## Contents |
40 | 12 |
|
41 | | -npm install |
42 | | -npm run build |
43 | | -``` |
| 13 | +- [Content architecture](#content-architecture) |
| 14 | +- [Localization](#localization) |
| 15 | +- [SEO](#seo) |
| 16 | +- [LLM usage analytics](#llm-usage-analytics) |
| 17 | +- [Local development](#local-development) |
| 18 | +- [Testing & code quality](#testing--code-quality) |
| 19 | +- [Deployment](#deployment-laravel-cloud) |
| 20 | +- [Key packages](#key-packages) |
44 | 21 |
|
45 | | -If you want to use Valet to serve your application, you can run the following command: |
| 22 | +## Content architecture |
46 | 23 |
|
47 | | -```bash |
48 | | -valet link |
49 | | - |
50 | | -valet secure |
| 24 | +Almost everything editorial — pages, news articles, team members, services, products, technologies, network partners, the AI model catalogue — lives as YAML or Markdown files under `database/files/`, not as data entered through a CMS. The files are the source of truth; the database is a rebuildable cache of them. |
51 | 25 |
|
52 | | -valet open |
53 | 26 | ``` |
54 | | - |
55 | | -If you want to user Herd to serve your application, you can run the following command: |
56 | | - |
57 | | -```bash |
58 | | -herd link |
59 | | - |
60 | | -herd secure |
61 | | - |
62 | | -herd open |
| 27 | +database/files/ |
| 28 | +├── ai_models/ one YAML file per model |
| 29 | +├── networks/ one YAML file per partner |
| 30 | +├── news/{locale}/ one Markdown file per article, per language |
| 31 | +├── pages/ one YAML file per page (SEO metadata: title, description, robots, image) |
| 32 | +├── products/{locale}/ |
| 33 | +├── services/{locale}/ |
| 34 | +├── team/ one YAML file per person |
| 35 | +└── technologies/{locale}/ |
63 | 36 | ``` |
64 | 37 |
|
65 | | -You can run the development asset server with the following command: |
| 38 | +Each content type has a matching import command that reads its files and upserts the database, and is safe to run repeatedly: |
66 | 39 |
|
67 | | -```bash |
68 | | -npm run dev |
69 | | -```` |
| 40 | +| Command | Reads | |
| 41 | +|---|---| |
| 42 | +| `php artisan pages:import` | `database/files/pages/*.yaml` | |
| 43 | +| `php artisan news:import` | `database/files/news/{locale}/*.md` | |
| 44 | +| `php artisan team:import` | `database/files/team/*.yaml` | |
| 45 | +| `php artisan services:import` | `database/files/services/{locale}/*.md` | |
| 46 | +| `php artisan products:import` | `database/files/products/{locale}/*.md` | |
| 47 | +| `php artisan technologies:import` | `database/files/technologies/{locale}/*.md` | |
| 48 | +| `php artisan networks:import` | `database/files/networks/*.yaml` | |
| 49 | +| `php artisan ai-models:import` | `database/files/ai_models/*.yaml` | |
| 50 | +| `php artisan sync:repositories` | live GitHub repositories (open-source content) | |
70 | 51 |
|
71 | | -> Note: You should set `valetTls: 'your-domain.test',` below `refresh: true,` in your `vite.config.js` file if you use `valet secure` or `herd secure`. |
| 52 | +`database/seeders/DatabaseSeeder.php` calls every one of these on `db:seed` — including in production. That is intentional: these seeders don't generate test fixtures, they publish the real content the same way running the command by hand would. The one exception is `AiModelDailyUsagesTableSeeder`, which loads a static local-dev fixture rather than real usage data (see [LLM usage analytics](#llm-usage-analytics)). |
72 | 53 |
|
73 | | -## Assets |
| 54 | +A file that disappears from `database/files/` removes the matching row on the next import — the importers are the single source of truth in both directions. |
74 | 55 |
|
75 | | -Assets should be set in the following directories: |
| 56 | +## Localization |
76 | 57 |
|
77 | | -- `resources/js` for JavaScript files. |
78 | | -- `resources/css` for CSS files. |
79 | | -- `resources/fonts` for Font files. |
80 | | -- `resources/images` for Image files. |
| 58 | +The site ships in German (`de_CH`) and English (`en_CH`) under distinct, fully translated URL prefixes rather than a shared `/en/…` segment — e.g. `/dienstleistungen` and `/services`, `/aktuelles` and `/news`, `/ueber-uns` and `/about-us`. Every localized route pair cross-references the other via `hreflang`, including on detail pages where the slug itself is translated (`routes/web.php`, `resources/views/layouts/_partials/_seo.blade.php`). |
81 | 59 |
|
82 | | -After you have added your assets, you can run the following command to compile them: |
83 | | -```bash |
84 | | -npm run build |
85 | | -``` |
| 60 | +## SEO |
86 | 61 |
|
87 | | -To include your assets in your blade files, you can use the following: |
| 62 | +- **Structured data** — a single `@graph` JSON-LD payload (`App\Seo\SchemaGraph` / `App\Seo\SchemaNodes`) built from `config/company.php`, the one source of truth for the company's name, addresses, phone and `sameAs` profiles. Every page ships `Organization`, `WebSite`, `WebPage` and `BreadcrumbList` nodes; content pages add `Service`, `Person`, `BlogPosting`, etc. |
| 63 | +- **Sitemap** — `App\Sitemap\SitemapBuilder` + `App\Http\Controllers\Sitemap\SitemapController` build `/sitemap.xml` from the same models the site renders, cached 24h via `Cache::remember`. |
| 64 | +- **Response cache** — `spatie/laravel-responsecache` caches full HTTP responses for up to 7 days. `App\Observers\SitemapCacheObserver` drops the sitemap's own data cache on every relevant model save, and `responsecache:clear` runs hourly via the scheduler (`routes/console.php`) as a backstop for the full-page cache layer — these are two independent caches and both need clearing after a bulk content change (`php artisan responsecache:clear` after a fresh `db:seed`, for instance). |
| 65 | +- **Social images** — article heroes that are local SVG placeholders (no real photography yet) are not usable as `og:image` — social crawlers don't render SVG. `App\Support\NewsImage::ogImage()` falls back to a same-named `.png` rendered from the SVG when one exists, or the site's default share image otherwise. |
| 66 | +- **Tests** — `tests/Feature/Seo/` asserts on the actual rendered JSON-LD and meta tags (not just "does it look right"), and `tests/lighthouse/` audits real Lighthouse scores against the built (`npm run build`) output, not the Vite dev server. |
88 | 67 |
|
89 | | -```blade |
90 | | -{{ Vite::asset('resources/images/your-image.png') }} |
91 | | -``` |
| 68 | +## LLM usage analytics |
92 | 69 |
|
93 | | -## Auth |
| 70 | +`/ki` (`/ai`) publishes aggregate usage figures for the AI models codebar runs internally via a self-hosted [LiteLLM](https://www.litellm.ai/) proxy. `php artisan llm:fetch-analytics` pulls per-day usage from the proxy's `/spend/logs` endpoint and stores it in `ai_model_daily_usages`; it's scheduled hourly but only backfills the last 3 days by default — use `--full` (syncs from 2026-01-01) or `--from`/`--to` to backfill a specific range. Spend figures are stored but must never be displayed publicly. The dashboard intentionally shows monthly/yearly aggregates only, never a daily breakdown. |
94 | 71 |
|
95 | | -Auth is enabled by default. |
| 72 | +## Local development |
96 | 73 |
|
97 | | -You can configure auth settings in the `config/laravel-auth.php` file. |
| 74 | +```bash |
| 75 | +composer install |
| 76 | +cp .env.example .env |
| 77 | +php artisan key:generate |
98 | 78 |
|
99 | | -### 🔐 Verify |
100 | | -If you wish to use email verification, you can use the following middleware to protect your routes: |
| 79 | +php artisan migrate --seed # imports real content — see "Content architecture" above |
101 | 80 |
|
102 | | -```php |
103 | | -Route::middleware(['laravel-auth-middleware'])->group(function () { |
104 | | - ... |
105 | | -}); |
106 | | -``` |
107 | | -To use verification in nova, add the middleware into in your `nova.php` config: |
108 | | - |
109 | | -```php |
110 | | -/* |
111 | | -|-------------------------------------------------------------------------- |
112 | | -| Nova Route Middleware |
113 | | -|-------------------------------------------------------------------------- |
114 | | -| |
115 | | -| These middleware will be assigned to every Nova route, giving you the |
116 | | -| chance to add your own middleware to this stack or override any of |
117 | | -| the existing middleware. Or, you can just stick with this stack. |
118 | | -| |
119 | | -*/ |
120 | | -
|
121 | | -'middleware' => [ |
122 | | - 'web', |
123 | | - 'laravel-auth-middleware', |
124 | | - HandleInertiaRequests::class, |
125 | | - DispatchServingNovaEvent::class, |
126 | | - BootTools::class, |
127 | | -], |
| 81 | +npm install |
| 82 | +npm run build # or `npm run dev` for the Vite dev server |
128 | 83 | ``` |
129 | 84 |
|
130 | | -### Microsoft Office 365 Authentication |
131 | | - |
132 | | -⚠️ When using Office 365 you need to provide a publicly accessible URL for the `MICROSOFT_REDIRECT_URI` environment variable. You can use [expose](https://expose.dev/) or [ngrok](https://ngrok.com/) for local development. |
133 | | - |
134 | | -```bash |
135 | | -APP_URL=https://your-expose-or-ngrok-url.com |
| 85 | +If you use [Herd](https://herd.laravel.com): |
136 | 86 |
|
137 | | -# ✅ This is recommended for production as well: |
138 | | -MICROSOFT_REDIRECT_URI="${APP_URL}/auth/service/microsoft/redirect" |
| 87 | +```bash |
| 88 | +herd link |
| 89 | +herd secure |
| 90 | +herd open |
139 | 91 | ``` |
140 | 92 |
|
141 | | -## Permissions |
142 | | - |
143 | | -Please refer to the [Spatie Permission](https://github.com/spatie/laravel-permission) documentation for more information on how to use permissions. |
144 | | - |
145 | | -## Enums |
146 | | - |
147 | | -Enums are included in PHP's core functionality but we have some additional functionality to make them easier to use. |
148 | | -
|
149 | | -You can create an enum in the `app/Enums` directory: |
150 | | -
|
151 | | -```php |
152 | | -<?php |
153 | | -
|
154 | | -namespace App\Enums; |
155 | | -
|
156 | | -use App\Interfaces\LabelEnumInterface;use App\Traits\HasLabels; |
157 | | -
|
158 | | -enum EnvironmentEnum: string implements LabelEnumInterface |
159 | | -{ |
160 | | - use HasLabels; |
161 | | -
|
162 | | - case PRODUCTION = 'production'; |
163 | | - case STAGING = 'staging'; |
164 | | - case LOCAL = 'local'; |
| 93 | +If you use [Valet](https://laravel.com/docs/valet): |
165 | 94 |
|
166 | | - public function label(): string |
167 | | - { |
168 | | - return match ($this) { |
169 | | - EnvironmentEnum::PRODUCTION => __('Production'), |
170 | | - EnvironmentEnum::STAGING => __('Staging'), |
171 | | - EnvironmentEnum::LOCAL => __('Local'), |
172 | | - }; |
173 | | - } |
174 | | -} |
| 95 | +```bash |
| 96 | +valet link |
| 97 | +valet secure |
| 98 | +valet open |
175 | 99 | ``` |
176 | 100 |
|
177 | | -You should use the `HasLabels` trait to add a `label` method to your enum. |
178 | | -You should also implement the `LabelEnumInterface` interface to ensure that the `label` method is implemented. |
179 | | -
|
180 | | -The `label` method should return the label for the enum value. |
181 | | -
|
182 | | -You can use the enum in your code like this: |
183 | | -
|
184 | | -```php |
185 | | -// Native PHP Enum |
186 | | -$enum = EnvironmentEnum::PRODUCTION; // Enum Object |
187 | | -$name = EnvironmentEnum::PRODUCTION->name; // Enum Name (PRODUCTION) |
188 | | -$value = EnvironmentEnum::PRODUCTION->value; // Enum Value (production) |
| 101 | +> Set `valetTls: 'your-domain.test'` below `refresh: true` in `vite.config.js` if you use `valet secure` / `herd secure`. |
189 | 102 |
|
190 | | -// Label |
191 | | -$label = EnvironmentEnum::PRODUCTION->label(); // Enum Label using Laravels Translation (Production) |
| 103 | +## Testing & code quality |
192 | 104 |
|
193 | | -// Labels |
194 | | -$labels = EnvironmentEnum::labels(); // Array of Enum Labels with Enum value as Key (['production' => 'Production', 'staging' => 'Staging', 'local' => 'Local']) |
| 105 | +```bash |
| 106 | +./vendor/bin/pest # test suite (Pest) |
| 107 | +./vendor/bin/phpstan analyse # static analysis (Larastan, see phpstan.neon.dist) |
| 108 | +./vendor/bin/pint # code style |
| 109 | +./vendor/bin/pint --blade # blade formatting (beta) |
195 | 110 | ``` |
196 | 111 |
|
197 | | -## Health |
198 | | -
|
199 | | -Please refer to the [Spatie Health](https://github.com/spatie/laravel-health) documentation for more information on how to use health checks. |
200 | | -
|
201 | | -We have added two health checks which are located in the `app/Checks` directory: |
202 | | -
|
203 | | -- `FailedJobsCheck` |
204 | | -- `JobsCheck` |
205 | | -
|
206 | | -## Helpers |
207 | | -
|
208 | | -We have added some helper functions which are located in the `app/Helpers` directory |
209 | | -
|
210 | | -You should the Facades for the helpers which are located in the `app/Helpers/Facades` directory: |
211 | | -
|
212 | | -- `HelperBank` |
213 | | -- `HelperDate` |
214 | | -- `HelperDevice` |
215 | | -- `HelperFile` |
216 | | -- `HelperMarkdown` |
217 | | -- `HelperMoney` |
218 | | -- `HelperNumber` |
219 | | -- `HelperPhone` |
220 | | -
|
221 | | -## Feature Policy |
222 | | -
|
223 | | -We have added feature policy which is located in the `app/FeaturePolicy` directory. |
224 | | -
|
225 | | -It is enabled by default and you can configure it in the `config/feature-policy.php` and `config/default.php` file. |
226 | | -
|
227 | | -The Feature Policy Middleware is installed and enabled by default in the `bootstrap/app.php` file. |
228 | | -
|
229 | | -## Traits |
230 | | -
|
231 | | -We have added some traits which are located in the `app/Traits` directory. |
232 | | -
|
233 | | -- `HassUuid` |
234 | | -
|
235 | | -We also have some traits which are located in the `app/Traits/Nova` directory which are intended for use only in Laravel Nova. |
236 | | -
|
237 | | -- `NovaCustomOrderTrait` |
238 | | -- `NovaIdentificationPanelTrait` |
239 | | -- `NovaLanguageTrait` |
240 | | -- `NovaTimestampsPanelTrait` |
241 | | -
|
242 | | -## Blade Components |
243 | | -
|
244 | | -We have added some blade components which are located in the `resources/views/components` directory. |
| 112 | +## Deployment (Laravel Cloud) |
245 | 113 |
|
246 | | -- `fathom.blade.php` |
247 | | -- `favicons.blade.php` |
248 | | -
|
249 | | -You should include both the blade components in your blade layout files |
250 | | -
|
251 | | -## Laravel Cloud deployment |
252 | | -
|
253 | | -When deploying to Laravel Cloud, ensure these environment variables are set for Lighthouse Best Practices (security headers): |
| 114 | +The site runs on [Laravel Cloud](https://cloud.laravel.com), behind Cloudflare. Required environment variables for security headers: |
254 | 115 |
|
255 | 116 | - `CSP_ENABLED=true` — enables Content-Security-Policy enforcement via Spatie CSP middleware |
256 | 117 | - `FPH_ENABLED=true` — enables Permissions-Policy headers |
257 | 118 |
|
258 | | -Security headers (HSTS, COOP, `X-Content-Type-Options`, `Referrer-Policy`, `X-Frame-Options`) are applied automatically by `SecurityHeaders` middleware on all web responses. |
259 | | -
|
260 | | -**Lighthouse note:** Deprecated API warnings for `/cdn-cgi/challenge-platform/scripts/jsd/main.js` come from Cloudflare bot protection injected by Laravel Cloud, not from application code. Run Lighthouse in incognito without browser extensions for accurate scores. |
261 | | -
|
262 | | -## Cloudinary |
263 | | -
|
264 | | -Please refer to the respective documentation for the Cloudinary and Cloudinary Nova packages. |
265 | | -
|
266 | | -- [Flysystem Cloudinary](https://github.com/codebar-ag/laravel-flysystem-cloudinary). |
267 | | -- [Flysystem Cloudinary Nova](https://github.com/codebar-ag/laravel-flysystem-cloudinary-nova). |
| 119 | +HSTS, COOP, `X-Content-Type-Options`, `Referrer-Policy` and `X-Frame-Options` are applied automatically by the `SecurityHeaders` middleware on every web response. |
268 | 120 |
|
269 | | -## Notifications |
| 121 | +**Lighthouse note:** deprecated-API warnings for `/cdn-cgi/challenge-platform/scripts/jsd/main.js` come from Cloudflare's bot protection, injected at the edge — not from application code. Run Lighthouse in incognito without extensions for an accurate score, and prefer `tests/lighthouse/` (which audits the built output) over ad-hoc runs against the dev server. |
270 | 122 |
|
271 | | -We use Filament for notifications. Please refer to the [Filament](https://filamentphp.com/docs/3.x/notifications/sending-notifications) documentation for more information on how to use notifications. |
272 | | -
|
273 | | -## Pint |
274 | | -
|
275 | | -We use Laravel Pint to format code. |
276 | | -
|
277 | | -You can run the following command to format your code: |
278 | | -
|
279 | | -```bash |
280 | | -./vendor/bin/pint |
281 | | -``` |
282 | | -
|
283 | | -You can run the following command to format your blade files: |
284 | | -
|
285 | | -```bash |
286 | | -./vendor/bin/pint --blade |
287 | | -``` |
288 | | -
|
289 | | -> The blade formatter is still in beta and may not work as expected. if you wish to not use this update your `composer.json` to use the latest version of `laravel/pint` instead of the dev branch. |
290 | | -
|
291 | | -
|
292 | | -## Testing |
293 | | -
|
294 | | -We use PestPHP for testing. |
295 | | -
|
296 | | -You can run the following command to run your tests: |
297 | | -
|
298 | | -```bash |
299 | | -./vendor/bin/pest |
300 | | -``` |
| 123 | +## Key packages |
301 | 124 |
|
302 | | -Please refer to the [PestPHP](https://pestphp.com) documentation for more information on how to use PestPHP. |
| 125 | +- **Content & storage** — `spatie/laravel-translatable`, `codebar-ag/laravel-flysystem-cloudinary` (editorial images), `league/flysystem-aws-s3-v3` (DigitalOcean Spaces for other assets), `symfony/yaml` |
| 126 | +- **SEO** — `spatie/laravel-sitemap`, `spatie/laravel-responsecache` |
| 127 | +- **Security & health** — `spatie/laravel-csp`, `spatie/laravel-honeypot`, `spatie/laravel-permission`, `spatie/laravel-health`, `spatie/security-advisories-health-check`, `mazedlx/laravel-feature-policy` |
| 128 | +- **Ops** — `laravel/nightwatch` (observability), `symfony/postmark-mailer` |
| 129 | +- **Analytics** — [Fathom](https://usefathom.com) (privacy-friendly, no cookie banner) |
303 | 130 |
|
304 | 131 | ## License |
305 | 132 |
|
306 | | -The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). |
| 133 | +The application code is proprietary to codebar Solutions AG. The underlying Laravel framework is open-source software licensed under the [MIT license](https://opensource.org/licenses/MIT). |
0 commit comments