Thank you for your interest in improving AuthentiChain. This project is a supply-chain integrity platform where correctness and security properties are enforced in the database layer, not the browser. Contributions that look harmless in a typical web app — an extra table write, a client-side role check, a convenience hash computed in React — can silently break guarantees that the whole product depends on. Read this guide before writing code; it compresses the project's binding development rules into the workflow you need to follow.
Please discuss first. Open an issue (or comment on an existing one) describing the change you want to make before investing significant effort. Large features, schema changes, anything touching RPCs/RLS, and anything touching the smart contract require prior agreement on approach.
By participating you agree to abide by the Code of Conduct.
- Before You Contribute
- Development Environment Setup
- Repository Structure
- Branching Strategy
- Coding Standards
- Testing Requirements
- Required Checks Before Every Push
- Dependency Changes
- Security-Sensitive Changes
- Commit Message Conventions
- Pull Request Process
- Review Requirements
- Documentation & Tracker Updates
- Reporting Bugs
- Reporting Security Vulnerabilities
- Code of Conduct
- License
- Read the README for the product model, architecture, and current status.
- Skim this guide end-to-end — especially Security-Sensitive Changes.
- Search existing issues and pull requests before opening a new one.
- Understand the trust model: the browser is untrusted. Authorization, hashing, state transitions, fraud detection, and protected mutations live in Postgres (RLS + SECURITY DEFINER RPCs). If your change moves any of that into React, it is wrong by definition.
Prerequisites:
- Node.js 20.19+ (22+ recommended) and npm
- A free Supabase project (backend)
- Optional: MetaMask + Sepolia test ETH for anchoring work; Foundry for contract work
git clone https://github.com/abhinav-phi/apas
cd apas
npm ci
cp .env.example .env # local environment file; fill in Supabase URL + anon keyBackend setup (SQL migrations in order, storage bucket, pg_cron/pgcrypto extensions, optional on-chain role grant) is documented step-by-step in MANUAL_STEPS.md. Do not invent your own migration order.
Start developing:
npm run dev # http://localhost:8080src/
├── components/ # layout/, charts/, ui/ (shadcn/Radix), shared components
├── contexts/ # AuthContext — auth state + server-assigned role
├── hooks/ # use-blockchain, use-pagination, use-debounce, use-toast
├── integrations/supabase/ # client.ts (THE only Supabase import path) + generated types.ts
├── lib/ # hash.ts · blockchain.ts · pdf.ts · i18n.ts · utils.ts
├── pages/ # 19 route components
└── test/ # Vitest suites
supabase/
├── migrations/ # initial CLI baseline snapshot (never re-run manually)
└── v3…v10 *.sql # ordered migration set (new migrations go here)
blockchain/product-auth-chain/ # Foundry project (ProductTracker.sol)
Note: the internal specification set under docs/ (product spec, tech spec, schema, rules, tracker) is maintained separately from this public repository. Where those documents matter for a contribution, this guide or the PR review will point you to the relevant rule.
- Branch from
main. - Name branches after the change type:
feat/csv-export-filters,fix/rate-limit-accounting,docs/setup-guide,chore/bump-vitest. - One logical change per branch/PR. Do not mix unrelated refactors into a feature PR.
- No
any. Ever. Use types from@/integrations/supabase/types.tsor declare local interfaces. Catch clauses are annotatedcatch (err: unknown)— keep it that way. - Single Supabase import path: always
import { supabase } from "@/integrations/supabase/client". Never re-export or create second clients. useEffecthygiene: depend on primitives (user?.id,rolestring), never on objects recreated each render. Every Realtime subscription effect MUST return cleanup:return () => supabase.removeChannel(channel);.- No production logging. Wrap debug output behind
import.meta.env.DEV; useconsole.erroronly for genuine failures; surface user-facing problems with toast notifications. - Error handling is mandatory. Every Supabase call handles
{ data, error }; never.then()without an error path. - Loading states are mandatory. Any page fetching data shows skeleton loaders.
- Design system: dark "Cosmic Dark" tokens only (
bg-background,bg-card, semantic colors) — no white backgrounds except QR render surfaces; monospace for hashes/codes/TX values; responsive at 375 px, 768 px, 1024 px+; grids stack on mobile. - Pagination: default page size 25, max 100; use
.range(from, to); never load unbounded lists. - Queries: select specific columns where practical; batch related reads with
Promise.all(); never query in a loop.
- Every table has RLS enabled with explicit policies. Never disable RLS, even temporarily.
- Append-only tables stay append-only.
supply_chain_eventsandscan_logsget SELECT policies only — never add UPDATE/DELETE policies, not even admin-only, and never add client INSERT policies (rows are written exclusively by SECURITY DEFINER RPCs). - No direct client writes to protected state. Clients hold no UPDATE grant on
products; recall/flag/unflag/anchor/claim/trust changes go through RPCs only. Do not add.update()calls against protected tables from the frontend. - Roles are server-assigned. Never insert/update
user_rolesfrom client code; roles come from the signup trigger whitelist oradmin_change_role(). - Migrations live in
supabase/, namedv{version}_{description}.sql, and MUST be idempotent (IF NOT EXISTS,CREATE OR REPLACE,DROP POLICY IF EXISTS). Include comments explaining each section. The baseline snapshot undersupabase/migrations/is historical — never modify or re-run it. - Never trust client input in SQL: validate in RPC bodies (ranges, formats, ownership); CHECK constraints are part of the design.
Every new or modified SECURITY DEFINER function MUST:
- Pin
SET search_path = ''and fully schema-qualify all references (public.products,auth.uid(),extensions.gen_random_bytes, …). - Prefer built-in
pg_catalogfunctions (sha256(convert_to(...))) over extension functions when possible — in-RPC hashing deliberately does not depend on pgcrypto. - Validate caller identity/role inside the function body (
auth.uid(),has_role(...)); definer rights bypass RLS, so the function IS the authorization boundary. - Lock contended rows explicitly (
SELECT ... FOR UPDATE) before read-modify-write sequences (see the event-hash chain and transfer flows for the pattern). - Return structured JSON results (
success, typed reasons) rather than raising on business-rule violations, matching the existing RPC style. - Grant
EXECUTEexplicitly (usually toauthenticatedonly; public access is reserved forverify_product_secure).
- Event and transfer hashes are computed server-side only, inside their RPCs, using the established formulas. Client-submitted hashes are discarded — do not reintroduce client-side hashing helpers (removed deliberately; regression tests guard this).
- Never change hash formulas without a migration plan for existing chains: stored
event_hash/previous_event_hashvalues must remain verifiable byte-for-byte. - Preserve chain linkage: first event
previous_event_hash = NULL, every later event references the previous hash; the partial UNIQUE index onprevious_event_hashprevents forks — don't defeat it. - Product codes (
PRD-XXXXXXXX) and batch codes (BAT-XXXXXX) formats are fixed by rule. - QR labels encode the verification URL (
{origin}/verify?code=…), never a bare code.
Contract work happens in blockchain/product-auth-chain/ (Solidity ^0.8.24, Foundry, optimizer 200 runs):
- Run
forge buildandforge testbefore proposing contract changes. ProductTracker.solis deployed and source-verified on Sepolia (0xA06470E128275c5fE4410d4A712F23d54c714b68). Any bytecode-changing modification implies a fresh deployment + Etherscan verification + updating the configured address — flag this in the PR before writing code.- RBAC on-chain is enum-based and owner-granted (
assignRole(address,uint8); Manufacturer = 2). Never suggest key-based or client-side role bypasses. - For live Sepolia calls always pass an explicit RPC:
--rpc-url $SEPOLIA_RPC_URL(repo Makefile defaults to a local Anvil endpoint). - Private keys and RPC secrets belong in local env files only — never in scripts, Makefiles, or commits.
- Add or update Vitest tests for any change to pure logic in
src/lib/(hash formats, conversions, URL builders, error mapping) and for regressions you fix. - Existing suites: hash/code/QR format guards, blockchain helpers, auth flow logic, verify flow logic — keep them green.
- Frontend behavior changes should ship with a manual test note in the PR (which pages, which roles, what you clicked).
- SQL changes cannot be exercised by Vitest; describe the exact SQL-editor/live-DB verification performed or planned (see below).
- Contract changes require
forge testoutput in the PR.
Run the full gate sequence; a PR will not be reviewed without it:
npm run lint # ESLint — expect 0 errors (8 pre-existing shadcn fast-refresh warnings are known)
npx tsc -b # TypeScript project build — must be clean
npm test # Vitest — all tests passing
npm run build # production build (PWA precache) — must succeed
npm audit # must report 0 vulnerabilitiesFor contract changes, additionally:
cd blockchain/product-auth-chain
forge build
forge testFix failures at the call site. Do not loosen types, disable rules, or weaken assertions to make an upgrade or refactor pass.
Per the project's dependency-hygiene rule:
npm ciandnpm run buildmust complete with zero deprecation warnings — replace deprecated direct dependencies and pin stale transitive ones viaoverrides(document why inpackage.json).- Required install scripts are approved via the
allowScriptsfield — extend it deliberately, never silence advisories wholesale. - After any dependency bump: rerun the full gate sequence above and fix breakage at call sites.
- State the motivation (CVE, deprecation, feature need) in the PR description.
The following areas require extra care and maintainer review:
| Area | Non-negotiables |
|---|---|
| RLS / grants | No policy removals or grant widenings without a written justification in the PR |
| SECURITY DEFINER RPCs | Pinned empty search_path, qualified refs, in-body authorization, row locks where contended |
| Hash chain | No formula/format changes; server-side computation preserved |
| Fraud engine | Thresholds (clone ≥10 distinct devices, rapid ≥5/5 min, travel >500 km/h, rate limit 10/min) only change with a documented rationale |
| Auth/roles | No new client-side role surfaces; trigger whitelist untouched |
| Blockchain honesty | No fake TX data; Etherscan links gated on blockchain_tx_status = 'confirmed'; pending/failed states preserved |
| Secrets | Only VITE_* public values in frontend config; service-role keys nowhere near client code |
If your change affects the trust model (what an attacker can/cannot do), spell out the before/after in the PR. Disclose honestly: implemented-in-code is not the same as verified-on-live-infrastructure, and PRs must not conflate the two.
Conventional commits, one logical change per commit:
feat: add analytics date-range export
fix: prevent duplicate realtime notification channels
chore: bump viem to 2.55.x (deprecation cleanup)
docs: expand MANUAL_STEPS storage-bucket policies
refactor(types): annotate catch clauses as unknown
test(hash): guard against client-side hasher reintroduction
Never: update, fix stuff, asdfg.
- Explain the change: what it does, why it's needed, and which issue it closes. Include screenshots/GIFs for UI changes.
- Update tests for any behavior or security-relevant change (Vitest for logic;
forge testfor contracts). - Update documentation when architecture, behavior, configuration, routes, RPC signatures, database schema, environment variables, deployment steps, or security rules change — this includes
README.mdandMANUAL_STEPS.md(e.g., new env keys or a new migration file means the runbook gets a row). - Disclose operational impact: list any new/changed SQL migrations, environment variables, dashboard settings (storage/extensions), or on-chain steps reviewers or operators must perform.
- Run the full gate sequence (above) and paste the results in the PR.
- Keep the task Tracker honest: the internal tracker (
docs/7. Tracker.md) is updated only when the corresponding work is actually verified — never mark live-database, cron, or end-to-end on-chain behavior as done because the code compiles. If you maintain the internal docs, mark items[x]only after execution; leave[~]/[ ]otherwise and say so in the PR. - Never claim unverified infrastructure behavior. "Applied in migration form" and "verified against the running database" are different statements; use the right one.
- Rebase onto
mainif needed; resolve conflicts in your branch.
- Every PR receives at least one maintainer review before merge.
- Security-sensitive changes (table above) additionally require a reviewer who is not the author and explicitly signs off on the security implications.
- Reviewers check, at minimum: rules compliance (no
any, RLS intact, RPC hygiene, hash discipline, dark-theme tokens, error/loading states), gate results, documentation/disclosure completeness, and whether claims match reality. - Address feedback via additional commits; squash-merge decisions rest with the maintainer.
- CI/manual review may request a live-DB demonstration for SQL-heavy changes before approval.
Documentation is part of the definition of done:
- README.md — user-facing behavior, setup, env vars, routes/RPC table.
- MANUAL_STEPS.md — anything an operator must do (migrations, dashboard settings, env, on-chain steps).
- Code comments explain why for non-obvious security decisions (e.g., why a hash is computed server-side).
- The internal spec/tracker set is updated by maintainers; if your PR invalidates something there (schema, RPC list, fraud thresholds), call it out so it can be synchronized.
Open a GitHub issue with:
- A clear title and one-paragraph summary.
- Steps to reproduce (include the route/page, role used, and exact input, e.g., product code format).
- Expected vs actual behavior.
- Console/network output (redact tokens, emails, wallet addresses, and any identifiers).
- Environment: browser + OS, and whether it reproduces on a fresh profile.
Search first; add to an existing issue rather than duplicating. Feature requests follow the same channel with a problem statement instead of repro steps.
Do not open public issues for security problems.
Email [PROJECT_CONTACT_EMAIL] with:
- Affected area (page, RPC, policy, contract function)
- Impact assessment (what an attacker gains)
- Reproduction steps or proof-of-concept
- Suggested fix, if any
You will receive an acknowledgment, followed by status updates as the issue is triaged and fixed. Coordinated disclosure is expected: please withhold public details until a fix ships and the advisory is published. Reporters of valid issues are credited unless they prefer anonymity. This project deals with product authenticity — social-engineering claims ("a manufacturer might lie") are tracked as roadmap/design topics, not vulnerabilities, unless they bypass a stated technical control.
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in this project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
Behavior that contributes to a positive environment:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community and the project's users
- Showing empathy toward other community members
Unacceptable behavior:
- Sexualized language or imagery, unwelcome sexual attention or advances
- Trolling, insulting or derogatory comments, personal or political attacks
- Public or private harassment
- Publishing others' private information without explicit permission
- Other conduct reasonably considered inappropriate in a professional setting
Maintainers clarify and enforce these standards and may remove, edit, or reject contributions — or temporarily/permanently ban contributors — for behavior they deem inappropriate, threatening, or harmful. This Code applies within project spaces and whenever someone officially represents the project publicly.
Report unacceptable behavior to [PROJECT_CONTACT_EMAIL]. All complaints are reviewed and investigated with confidentiality toward the reporter. Maintainers who do not follow or enforce this Code in good faith may face temporary or permanent repercussions as determined by project leadership.
Adapted from the Contributor Covenant, versions 1.4/2.x.
By contributing, you agree that your contributions are licensed under the MIT License that covers this repository.