Packages
The three shared TypeScript packages under packages/ back the two
React apps. All are namespaced under @civicos/* and consumed via
workspace:* — pnpm resolves them to symlinks so a change is visible
immediately without publishing.
@civicos/types
Purpose: the DTOs and enums that cross the frontend / backend boundary. Both apps import from here so a rename or a new enum member flows through TypeScript across the whole platform.
Contents you'll typically find:
UserRole,RequestedAccountType,ApprovalStatus— role and application enums that mirror the Go domain enums.IssueStatus,IssueCategory,PetitionStatus,NotificationType— community-scoped enums.- Request/response envelope types (
ApiSuccess<T>,ApiError). - Public entity shapes:
PublicUser,Community,Issue,Petition,Representative,Notification.
Rule: if a value crosses the wire, its type lives here. Don't
duplicate an interface between apps/web and apps/admin.
@civicos/config
Purpose: zod-validated access to import.meta.env for the two
frontends. Fails fast at startup if a required var is missing rather
than exploding later with an undefined URL.
Typical usage:
import { env } from '@civicos/config';
const apiClient = axios.create({
baseURL: env.VITE_API_URL, // typed as string, guaranteed non-empty
});
Add a new variable by extending the zod schema in
packages/config/src/index.ts. If you don't add it to the schema, the
frontend can't read it.
@civicos/ui
Purpose: shared React components used by both apps/web and
apps/admin. Buttons, form primitives, layout shells, empty-state
components — anything both apps benefit from being consistent about.
Keep app-specific components in each app's src/features/ folder.
Only extract to @civicos/ui when a component is actually used in
both apps — premature sharing creates coupling for no gain.
Consuming from an app
package.json in each app already lists the shared packages:
{
"dependencies": {
"@civicos/types": "workspace:*",
"@civicos/config": "workspace:*",
"@civicos/ui": "workspace:*"
}
}
Import from them like any other package:
import { IssueStatus, type PublicUser } from '@civicos/types';
import { Button } from '@civicos/ui';
Adding a new shared package
Follow the pattern in Monorepo → Adding a new frontend package.
What the packages are not
- Not a component library for external consumers. They're internal. No versioning, no changelog, no publish step — the workspace protocol handles everything.
- Not for backend code. The Go services don't consume them. If you
need a shared Go primitive, put it in each service's
pkg/folder, or accept the duplication.
Next: Contributing.