Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
4 changes: 3 additions & 1 deletion .github/workflows/coderabbit-approval.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,13 @@ jobs:
- name: Summary
if: steps.check-approval.outputs.is_coderabbit_approved == 'true'
uses: actions/github-script@v7
env:
LABEL_WAS_PRESENT: ${{ steps.remove-label.outputs.label_was_present }}
with:
github-token: ${{ secrets.EXTERNAL_LABELLER_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const prNumber = context.payload.pull_request.number;
const labelWasPresent = '${{ steps.remove-label.outputs.label_was_present }}' === 'true';
const labelWasPresent = process.env.LABEL_WAS_PRESENT === 'true';

console.log('='.repeat(50));
console.log('CodeRabbit Approval Handler Complete');
Expand Down
9 changes: 7 additions & 2 deletions .github/workflows/sync-pr-labels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,12 @@ jobs:
- name: Apply issue-based labels
if: steps.extract-issue.outputs.issue_number != ''
uses: actions/github-script@v7
env:
ISSUE_NUMBER: ${{ steps.extract-issue.outputs.issue_number }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const issueNumber = '${{ steps.extract-issue.outputs.issue_number }}';
const issueNumber = process.env.ISSUE_NUMBER;
const prNumber = context.payload.pull_request.number;

try {
Expand Down Expand Up @@ -133,11 +135,14 @@ jobs:

- name: Apply file-based labels
uses: actions/github-script@v7
# File names come from the PR author; pass them through env so they are never parsed as script source
env:
CHANGED_FILES: ${{ steps.changed-files.outputs.files }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = context.payload.pull_request.number;
const changedFiles = JSON.parse('${{ steps.changed-files.outputs.files }}');
const changedFiles = JSON.parse(process.env.CHANGED_FILES);

const fileLabels = [];

Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -365,3 +365,6 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

# security reviews with unremediated findings (never commit)
unremediated-security-reviews/
5 changes: 3 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Find out more at https://pictopy.aossie.org/.
- **Build:** `npm run build` (static export to `out/`)
- **Develop:** `npm run dev`
- **Lint:** `npm run lint`
- **Test:** `npm test` · `npm run test:coverage` (90% threshold, enforced in CI)
- **Test:** `npm test` · `npm run test:coverage` (90% threshold on the whole code base, every file in `src/`, enforced in CI; exclusions and their reasons are listed in [`vitest.config.mts`](vitest.config.mts)). Components and pages get React Testing Library render tests with the real catalogs; shared jsdom mocks are in [`tests/setup.ts`](tests/setup.ts).
- **Testable logic lives in [`src/lib/`](src/lib/):** keep hooks thin and put pure functions there, with unit and fast-check property tests in [`tests/`](tests/).

---
Expand All @@ -44,6 +44,7 @@ Find out more at https://pictopy.aossie.org/.
## 📦 Project Boundaries

- **Config alias map:** Webpack & Turbopack alias resolvers are manually defined in [`next.config.ts`](next.config.ts) mapping `"next-intl/config"` to our local request setup. Do not import the native `@swc/core` compiler plugin wrapper `createNextIntlPlugin` directly to avoid security policy native module blocks.
- **External links:** External links live in [`src/config/links.ts`](src/config/links.ts) (site origin in [`src/config/site.ts`](src/config/site.ts)); never hard-code URLs in components. Timer and tuning numbers used in one file are named constants at the top of that file.
- **Branding Assets:** The official branding logo, favicon, and style specifications reside inside [`public/brand/`](public/brand/). The social share image is [`public/og-image.png`](public/og-image.png) (1200x630 PNG; never point Open Graph at an SVG).
- **Root route:** [`src/app/(root)/`](src/app/(root)/) serves the bare `/` with the default locale's metadata and a `<meta http-equiv="refresh">` to `/en`. Do not replace it with `redirect()`, which exports an empty error page.
- **Root route:** [`src/app/(root)/`](src/app/(root)/) serves the bare `/` with the default locale's metadata and an inline `location.replace("/en")` that runs as soon as it is parsed (the `<meta http-equiv="refresh">` and link are only a no-JS fallback; keep the `(root)` layout free of stylesheets so nothing delays it). Do not replace it with `redirect()`, which exports an empty error page.

2 changes: 1 addition & 1 deletion BestPracticesChecklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
- *Evidence URL:* `npm test` / `npm run test:coverage` (https://github.com/AOSSIE-Org/PictoPy-Website/blob/main/package.json)

- [x] 🔵 **test_most** — The test suite covers most code branches and functionality. *(SUGGESTED)*
- *Evidence URL:* https://github.com/AOSSIE-Org/PictoPy-Website/blob/main/vitest.config.mts (90% line/branch/function thresholds on logic modules, enforced in CI)
- *Evidence URL:* https://github.com/AOSSIE-Org/PictoPy-Website/blob/main/vitest.config.mts (coverage measured on the whole code base, every file in `src/` except type-only `*.d.ts`; 90% line/statement/function/branch thresholds enforced in CI; currently 100% lines, ~98% branches across unit, render and property tests)

### New Functionality Testing Policy

Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ Open [http://localhost:3000](http://localhost:3000). The site redirects to the d

```bash
npm run lint
npm run test:coverage # Vitest unit + property tests, 90% coverage threshold
npm run test:coverage # Vitest unit, render + property tests, 90% coverage threshold
npm run build # static export to out/
```

3. **Tests are required for new logic.** Anything in `src/lib/`, `src/hooks/`, `src/config/`, `src/i18n/` or `src/app/sitemap.ts` must come with tests in `tests/`. Use [fast-check](https://fast-check.dev) property tests where an input space is large (user agents, file names, URLs).
3. **Tests are required for new functionality.** Coverage is measured on the whole code base (every file in `src/`) and CI fails below 90% lines, statements, functions or branches. Only type-only `*.d.ts` files are excluded; the list, with the reason for each entry, is in [`vitest.config.mts`](vitest.config.mts), and new exclusions need a reason there. New logic in `src/lib/`, `src/hooks/`, `src/config/` or `src/i18n/` comes with unit tests, and new or changed components and pages come with React Testing Library render tests that use the real message catalogs (both locales where the copy differs). Use [fast-check](https://fast-check.dev) property tests where an input space is large (user agents, file names, URLs, click sequences). Shared mocks for what jsdom cannot run live in [`tests/setup.ts`](tests/setup.ts).
4. **Commit messages** follow [Conventional Commits](https://www.conventionalcommits.org) (`feat:`, `fix:`, `docs:`, `test:`, `chore:`), signed off with `-s`.
5. **Screenshots:** include before/after screenshots (light and dark, desktop and mobile) for any visual change.

Expand Down
86 changes: 86 additions & 0 deletions PRIVACY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Privacy Policy

**Last updated:** 1 November 2026

## Introduction

The PictoPy Website at [pictopy.aossie.org](https://pictopy.aossie.org) (the Website) is committed to protecting your privacy and providing a transparent and user-friendly experience.

This Privacy Policy explains how the Website handles information when you visit it.

The Website follows a privacy-conscious and local-first approach. It is a static website: it has no user accounts, no forms, no cookies, no analytics and no advertising.

This policy covers the Website only, not the PictoPy app. The app is developed in its own repository ([AOSSIE-Org/PictoPy](https://github.com/AOSSIE-Org/PictoPy)), and any privacy information for the app is published there.

## Official Downloads

The PictoPy app is officially available only from:

- [GitHub Releases (Windows, macOS and Linux)](https://github.com/AOSSIE-Org/PictoPy/releases/latest)

PictoPy is a desktop app; it is not distributed through any app store. Copies from other sources are not published by AOSSIE, and this policy does not cover them.

## Information and Permissions

The Website does not ask you for personal information and does not request any device permissions.

The Website saves the following in your browser's local storage:

- `theme`: your light or dark mode choice

This stays in your browser and is never sent to us.

## Data Storage

All information is stored locally on your device and is not uploaded to or maintained on any remote server.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved

## Data Sharing

The Website does not sell your personal information.

The Website does not use personal information for targeted advertising.

The Website relies on these third parties to work. Each one receives only what your browser sends to load the Website:

- **GitHub Pages** (hosting): GitHub receives your IP address and standard request details (such as your browser type and the page requested) whenever your browser loads the Website, and may keep them in server logs for security and operations. See [GitHub's Privacy Statement](https://docs.github.com/site-policy/privacy-policies/github-general-privacy-statement).
- **GitHub API** (download links): your browser asks `api.github.com` for the latest PictoPy release so the download buttons point to the newest version. GitHub receives your IP address with that request. See [GitHub's Privacy Statement](https://docs.github.com/site-policy/privacy-policies/github-general-privacy-statement).
- **Google Fonts** (typography): your browser loads the Inter font from `fonts.googleapis.com` and `fonts.gstatic.com`, so Google receives your IP address and browser details. See the [Google Fonts privacy FAQ](https://developers.google.com/fonts/faq/privacy).
- **Unsplash** (background photos): your browser loads the decorative photo grid from `images.unsplash.com` and `plus.unsplash.com`, so Unsplash receives your IP address and browser details. See [Unsplash's privacy policy](https://unsplash.com/privacy).

Links on the Website (AOSSIE, GitHub, GitHub Releases downloads, Discord and social media) take you to services with their own privacy policies.

The **Share** button in the footer opens the platform you choose (WhatsApp, X, LinkedIn, Telegram or your email app) with the address of the page you are on, or copies that address. That platform's own privacy policy applies to what you share there. The Website does not record what you share.

The **Support** page links to [GitHub Sponsors](https://github.com/sponsors/AOSSIE-Org). If you choose to donate, you do so on GitHub, and GitHub's privacy statement applies; The Website does not receive any payment details.

Where a third party processes information, its handling of that information is governed by its own privacy policy and terms of service.

## Data Security

The Website aims to minimize privacy and security risks by limiting unnecessary data collection and keeping your preferences on your device.

However, no method of electronic storage or transmission can be guaranteed to be completely secure. Users are also responsible for maintaining the security of their devices.

## Data Deletion

You can remove everything the Website stores by clearing your browser's site data for pictopy.aossie.org.

## Children's Privacy

The Website is not intended to knowingly collect personal information from children where such collection is prohibited by applicable law. It does not collect personal information from any visitor.

## Free Access

The Website is free to use and has no paid features.

## Changes to This Privacy Policy

We may update this Privacy Policy from time to time to reflect changes to the Website, its functionality, or applicable legal requirements.

Any updates will be made available wherever this Privacy Policy is published.

## Contact Us

If you have any questions or concerns about this Privacy Policy or the Website's privacy practices, please contact us at:

[contact@aossie.org](mailto:contact@aossie.org)
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
A high-performance, developer-friendly webpage built on **Next.js 16 (App Router)**, **React 19**, **Tailwind CSS v4**, and pre-configured for **Internationalization (i18n)** and **Localization (l10n)** using **next-intl**.

[![CI](https://github.com/AOSSIE-Org/PictoPy-Website/actions/workflows/ci.yml/badge.svg)](https://github.com/AOSSIE-Org/PictoPy-Website/actions/workflows/ci.yml)
[![Deploy](https://github.com/AOSSIE-Org/PictoPy-Website/actions/workflows/build-and-deploy.yaml/badge.svg)](https://github.com/AOSSIE-Org/PictoPy-Website/actions/workflows/build-and-deploy.yaml)
[![Deploy](https://github.com/AOSSIE-Org/PictoPy-Website/actions/workflows/nextjs.yml/badge.svg)](https://github.com/AOSSIE-Org/PictoPy-Website/actions/workflows/nextjs.yml)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/AOSSIE-Org/PictoPy-Website/badge)](https://scorecard.dev/viewer/?uri=github.com/AOSSIE-Org/PictoPy-Website)
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE)

Expand Down Expand Up @@ -207,7 +207,7 @@ Here is a breakdown of the key i18n directories and files:
│ └── messages/
│ ├── en.json
│ └── hi.json
├── tests/ # Vitest unit + property tests
├── tests/ # Vitest unit, render + property tests
├── tsconfig.json
├── vitest.config.mts
└── .gitignore
Expand Down Expand Up @@ -404,7 +404,13 @@ npm run test:watch # re-run on file changes
npm run test:coverage # run with coverage; fails below 90% (same as CI)
```

Tests live in [`tests/`](tests/) and cover platform detection, release-asset lookup, SEO metadata, the sitemap, the download/platform hooks and translation-catalog parity. They include [fast-check](https://fast-check.dev) property tests.
Tests live in [`tests/`](tests/). Coverage is measured on the **whole code base** (every file in `src/`: pages, layouts, components, hooks, config and helpers), and CI fails if lines, statements, functions or branches drop below 90%. The only exclusion is type-only declaration files (`*.d.ts`); the list, with a reason for each entry, is in [`vitest.config.mts`](vitest.config.mts).

- **Unit and logic tests** cover platform detection, release-asset lookup, SEO metadata, the sitemap, the download/platform hooks and translation-catalog parity.
- **Render tests** ([React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) in jsdom) render every component, page and layout with the real `en` and `hi` catalogs and check copy, links, ARIA state and interactions (navbar and mobile menu, theme toggle, language switcher, FAQ accordion, download buttons, share dialog). Server Components are rendered with React's server renderer, as the static export does.
- **Property tests** ([fast-check](https://fast-check.dev)) check invariants over generated inputs: user agents, release assets, sitemap and locale URLs, safe links in the legal documents, the FAQ accordion, language-switcher keyboard focus, theme toggling and the photo-grid shuffle.

Shared stand-ins for what jsdom cannot run (the Next.js router, `next/image`, `next/font`, `matchMedia`, observers) are in [`tests/setup.ts`](tests/setup.ts) and [`tests/helpers/`](tests/helpers/).

### Previewing the Static Export

Expand Down
56 changes: 56 additions & 0 deletions TERMS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Terms of Service

**Last updated:** 1 November 2026

## Introduction

These Terms of Service (the Terms) govern your use of the PictoPy Website at [pictopy.aossie.org](https://pictopy.aossie.org) (the Website), an open-source project of AOSSIE (Australian Open Source Software Innovation and Education).

By using the Website, you agree to these Terms. If you do not agree, please do not use the Website.

These Terms cover the Website only. The PictoPy app is a separate product, and its own license and policies apply to it. Download the app only from the official sources listed in our [Privacy Policy](PRIVACY.md).

## Open-Source License

The source code of the Website is published at [AOSSIE-Org/PictoPy-Website](https://github.com/AOSSIE-Org/PictoPy-Website) under the GPL-3.0 license. Your rights to use, copy, modify and distribute the source code are set by that license, and nothing in these Terms limits them.

## Acceptable Use

You may use the Website for any lawful purpose. You agree not to:

- break any applicable law while using it;
- interfere with or disrupt it, the infrastructure it runs on, or other people's use of it;
- attempt to gain unauthorized access to any system or data;
- use it to infringe the rights of others.

## Accounts and Content

The Website does not require an account and does not host content created by users.

## Third-Party Services

The Website links to and relies on third-party services, such as GitHub. We don't control them, and your use of them is governed by their own terms and privacy policies.

## Privacy

Our [Privacy Policy](PRIVACY.md) explains how the Website handles information.

## Disclaimer of Warranties

The Website is provided "as is" and "as available", without warranties of any kind, express or implied, including warranties of merchantability, fitness for a particular purpose, accuracy and non-infringement. We don't promise that it will always be available, error-free or secure.

## Limitation of Liability

To the maximum extent permitted by applicable law, AOSSIE and the project's maintainers and contributors are not liable for any indirect, incidental, special, consequential or punitive damages, or for any loss of data, profits or goodwill, arising from your use of, or inability to use, the Website.

Nothing in these Terms excludes or limits any liability, or any consumer right, that cannot be excluded or limited under applicable law.

## Changes to These Terms

We may change, suspend or discontinue the Website at any time. We may also update these Terms from time to time; any updates will be made available wherever these Terms are published. If you keep using the Website after an update, the updated Terms apply.

## Contact Us

If you have any questions about these Terms, please contact us at:

[contact@aossie.org](mailto:contact@aossie.org)
17 changes: 17 additions & 0 deletions audit/PeerReviewRemediationReport.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# PictoPy Website: Peer Review Remediation Report

| | |
|---|---|
| **Peer review** | [`audit/PeerReviewReport.md`](PeerReviewReport.md) (merged in [PR #39](https://github.com/AOSSIE-Org/PictoPy-Website/pull/39)) |
| **Reviewer** | Piyush ([@Piyushbijarania](https://github.com/Piyushbijarania)) |
| **Reviewed revision** | `main` @ [`f30fd89`](https://github.com/AOSSIE-Org/PictoPy-Website/commit/f30fd89ea773295e58058009c17a273956b1b476) |
| **Remediated by** | Saksham Jain ([@reach2saksham](https://github.com/reach2saksham)) |
| **Date** | 1 November 2026 |

## Summary

The peer review reported **no findings** for this revision, so there was nothing to remediate. Thank you to the reviewer for checking the project.

| Finding | Severity | Status |
|---|---|---|
| None reported | — | No action needed |
Binary file not shown.
Binary file added local-packages/support-us-button-2.3.0.tgz
Binary file not shown.
Loading
Loading