Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copy this file to .env.local and fill in the values.
# Never commit .env.local to source control.

# Feature flag overrides — takes priority over public/feature-flags.json.
# Set to 'true' or 'false' to force a flag in a specific environment.
NEXT_PUBLIC_FLAGS_NEW_SEARCH=
NEXT_PUBLIC_FLAGS_DRAFT_MODE=
NEXT_PUBLIC_FLAGS_RSS_FEED=
NEXT_PUBLIC_FLAGS_RELATED_POSTS=
NEXT_PUBLIC_FLAGS_CONTENT_REVISION_HISTORY=
17 changes: 17 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 10
labels:
- dependencies
- security
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
labels:
- dependencies
- ci
100 changes: 100 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: Deploy

on:
push:
branches:
- main # → production
- develop # → staging
pull_request:
types: [opened, synchronize, reopened] # → preview

jobs:
build:
runs-on: ubuntu-latest
outputs:
artifact-name: ${{ steps.set-name.outputs.name }}

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Build static export
run: npm run build
env:
NEXT_PUBLIC_SENTRY_DSN: ${{ secrets.NEXT_PUBLIC_SENTRY_DSN }}

- name: Set artifact name
id: set-name
run: echo "name=zoltraak-out-${{ github.sha }}" >> "$GITHUB_OUTPUT"

- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: ${{ steps.set-name.outputs.name }}
path: out/
retention-days: 7

deploy-preview:
if: github.event_name == 'pull_request'
needs: build
runs-on: ubuntu-latest
environment:
name: preview

steps:
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: ${{ needs.build.outputs.artifact-name }}
path: out/

# Replace with your actual preview deployment step, e.g.:
# - uses: cloudflare/pages-action@v1
# - uses: vercel/action@v1
- name: Deploy to preview (placeholder)
run: echo "Deploy ./out to preview environment here"

deploy-staging:
if: github.ref == 'refs/heads/develop' && github.event_name == 'push'
needs: build
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging.tu2l.com/zoltraak

steps:
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: ${{ needs.build.outputs.artifact-name }}
path: out/

- name: Deploy to staging (placeholder)
run: echo "Deploy ./out to staging environment here"

deploy-production:
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
needs: build
runs-on: ubuntu-latest
environment:
name: production
url: https://www.tu2l.com/zoltraak

steps:
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: ${{ needs.build.outputs.artifact-name }}
path: out/

- name: Deploy to production (placeholder)
run: echo "Deploy ./out to production environment here"
75 changes: 75 additions & 0 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Quality Checks

on:
push:
branches:
- main
pull_request:

jobs:
lint-and-audit:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Run lint
run: npm run lint

- name: Run npm audit
run: npm audit --audit-level=high

smoke-tests:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Install Playwright browsers
run: npx playwright install --with-deps chromium

- name: Run smoke tests
run: npm run test:e2e

lighthouse-ci:
runs-on: ubuntu-latest
needs: smoke-tests

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Build static export
run: npm run build

- name: Run Lighthouse CI
run: npx @lhci/cli@0.14.x autorun
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

# testing
/coverage
/playwright-report
/test-results

# next.js
/.next/
Expand Down
44 changes: 44 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is inspired by Keep a Changelog and this project follows Semantic Versioning.

## [Unreleased]

### Added
- Roadmap and architecture decision records under `docs/`.
- Shared route helper and navigation utility modules.
- Runtime config validation layer for app and public configuration payloads.
- Shared async loading/error/empty state components.
- Playwright smoke tests plus CI workflow coverage for key routes.
- Shared SEO metadata utility with per-route metadata exports and homepage JSON-LD structured data.
- Accessibility checklist document and keyboard-focus improvements for major interactive card components.
- Core Web Vitals telemetry via `useReportWebVitals` hook (`src/components/WebVitals.js`).
- Lighthouse CI performance budgets (`lighthouserc.js`) and CI job in `quality.yml`.
- Migrated thumbnail rendering in `Item.js` to `next/image` for lazy-loading and CLS prevention.
- Sentry client-side error and performance tracking scaffold (`src/lib/sentry.js`, `SentryProvider`).
- `.env.example` with `NEXT_PUBLIC_SENTRY_DSN` placeholder.
- Reusable `CardBase` and `ItemList` layout primitives (`src/components/common/`).
- Feature flag framework (`src/lib/flags.js`) with JSON file, env override, and `useFlag` hook.
- `public/feature-flags.json` runtime flag defaults.
- Taxonomy schema and content validators (`src/lib/taxonomy.js`).
- Reading-time estimator and related-posts helper (`src/lib/content-utils.js`).
- Static `public/sitemap.xml` for all known routes.
- Client-side search page (`/search`) with instant filtering and `ItemList` layout.
- `DraftBadge` component gated by DRAFT_MODE feature flag.
- ADR-0002 documenting content revision history strategy.
- Deployment environment matrix (`docs/DEPLOYMENT_MATRIX.md`) with preview/staging/prod tiers.
- GitHub Actions `deploy.yml` workflow with per-environment jobs.

### Changed
- Migrated `/pages` navigation flows to Next router/search params hooks.
- Standardized internal topic/post route generation.

### Fixed
- Reduced brittle internal URL handling patterns.

## [0.1.0] - 2026-04-25

### Added
- Initial alpha release of Zoltraak.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ npm run build
npm start
```

### Quality Checks

```bash
# Lint the project
npm run lint

# Run dependency audit
npm run audit

# Run Playwright smoke tests
npx playwright install chromium
npm run test:e2e
```

## Configuration

All configuration files are located in the `/config` and `/public` directories. Update these files to customize your site:
Expand Down Expand Up @@ -170,6 +184,7 @@ Zoltraak requires a backend repository to serve content. The default backend is
- **React 19** - UI library
- **Material-UI 6** - Component library
- **DOMPurify** - XSS protection for user content
- **Playwright** - Route smoke tests

## Contributing

Expand Down
2 changes: 1 addition & 1 deletion config/api.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"baseUrl": "http://127.0.0.1:8080/published",
"baseUrl": "https://www.tu2l.com/zoltraak-backend/",
"endpoints": {
"pages": "/page.json",
"server": "server.json"
Expand Down
2 changes: 1 addition & 1 deletion config/menu.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"title": "Zoltraak",
"title": "Tu2l",
"menuItems": [
{
"name": "Home",
Expand Down
12 changes: 8 additions & 4 deletions config/themes.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
[
{
"palette": {
"type": "light",
"mode": "light",
"primary": {
"main": "#fff"
"main": "#1976d2"
},
"secondary": {
"main": "#9c27b0"
},
"divider": "#000",
"background": {
"default": "#fafafa",
"paper": "#fff"
},
"text": {
"primary": "#000"
}
}
},
{
"palette": {
"type": "dark",
"mode": "dark",
"primary": {
"main": "#000"
"main": "#90caf9"
},
"secondary": {
"main": "#9c27b0"
Expand Down
42 changes: 42 additions & 0 deletions docs/ACCESSIBILITY_CHECKLIST.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Accessibility Checklist

Use this checklist before merging UI changes.

## Semantics
- Use native interactive elements (`button`, `a`) for click/keyboard interactions.
- Ensure heading hierarchy is logical (`h1` -> `h2` -> `h3`) and page has a clear primary heading.
- Prefer `main`, `nav`, `section`, and `footer` landmarks where appropriate.

## Keyboard Navigation
- Every interactive element must be reachable via Tab.
- Enter/Space must activate all custom interactive controls.
- Focus order must match visual order.
- Add visible focus styles (`:focus-visible`) for interactive UI elements.

## Links and Buttons
- Internal navigation should use client routing where possible.
- External links opening in new tabs should use `rel="noopener noreferrer"`.
- Ensure clickable cards expose meaningful accessible names (`aria-label` where needed).

## Color and Contrast
- Verify text contrast against background in light and dark themes.
- Verify focus indicators meet contrast requirements.

## Content and States
- Loading, empty, and error states should be announced clearly in visible text.
- Error messages should be actionable and specific.
- Avoid relying on color alone to communicate status.

## Media
- Provide descriptive `alt` text for informative images.
- Decorative images should use empty alt text.

## Testing Routine
1. Run `npm run lint`.
2. Run `npm run test:e2e`.
3. Navigate key routes (`/`, `/pages`, `/projects`, `/tools`) using keyboard only.
4. Validate at 200% zoom and mobile viewport.

## Optional Advanced Checks
- Run Lighthouse accessibility audit.
- Test with a screen reader (NVDA/Orca/VoiceOver).
Loading
Loading