654 lines
15 KiB
Markdown
654 lines
15 KiB
Markdown
# AGENT.md
|
|
|
|
## Overview
|
|
|
|
This project is a mobile-first web application for an advertising agency to organize editorial calendars, important dates, deliveries, assets, and client-facing planning.
|
|
|
|
The main goal is to replace the current messy Trello workflow with a centralized, secure, responsive application where:
|
|
|
|
- agency staff can view and manage all clients they are allowed to access;
|
|
- each client can access only their own area;
|
|
- the calendar shows Brazilian national holidays, commemorative dates, and custom dates;
|
|
- specific days can contain content such as post copy, images, notes, status, and attachments;
|
|
- the dashboard includes a weekly overview so the team can quickly understand what is done and what is still pending.
|
|
|
|
The application itself must be fully localized in Brazilian Portuguese (`pt-BR`). Project documentation and developer-facing instructions may be written in English unless explicitly requested otherwise.
|
|
|
|
## Audience
|
|
|
|
- Internal users: advertising team, social media team, account managers, designers, managers, and administrators.
|
|
- External users: agency clients, initially with read-only access.
|
|
- Product tone: clear, professional, direct, and operational.
|
|
- UI language: Brazilian Portuguese (`pt-BR`).
|
|
|
|
## Technical Stack
|
|
|
|
### Frontend
|
|
|
|
- JavaScript.
|
|
- React 19.
|
|
- shadcn/ui.
|
|
- Mobile-first and fully responsive.
|
|
- UI text in `pt-BR`.
|
|
- Accessible components, including keyboard navigation where applicable.
|
|
|
|
### Backend
|
|
|
|
- Go 1.25.
|
|
- Gin.
|
|
- REST API.
|
|
- Strong input validation.
|
|
- Authentication and role-based authorization.
|
|
- Clean, readable, modular structure.
|
|
|
|
### Infrastructure
|
|
|
|
- Repository: Gitea.
|
|
- Hosting: Portainer.
|
|
- Configuration: environment variables only.
|
|
- Delivery: Dockerfile, Docker Compose, and CI/CD pipelines.
|
|
|
|
## Product Identity
|
|
|
|
- Project name: `Mira`.
|
|
- Main brand color: orange.
|
|
- The UI must support light and dark themes.
|
|
- Theme switching must be available in the authenticated application shell.
|
|
- The design should feel operational and polished, not like a marketing landing page.
|
|
|
|
## User Roles
|
|
|
|
### Super Admin
|
|
|
|
The main administrative user for the agency.
|
|
|
|
- Created from Portainer environment variables.
|
|
- Can access all clients.
|
|
- Can create, edit, and remove users.
|
|
- Can create email invitations.
|
|
- Can manage clients, calendars, custom dates, and content.
|
|
- Can grant access to internal users and clients.
|
|
|
|
Expected variables:
|
|
|
|
- `SUPER_ADMIN_EMAIL`
|
|
- `SUPER_ADMIN_PASSWORD`
|
|
|
|
### Agency User
|
|
|
|
Internal operational user.
|
|
|
|
- Can view assigned clients.
|
|
- Can create and edit calendar content according to permissions.
|
|
- Can view the weekly dashboard.
|
|
- Can attach assets to calendar days.
|
|
- Can update delivery/content statuses.
|
|
|
|
### Client Viewer
|
|
|
|
External user linked to a specific client.
|
|
|
|
- Can log in.
|
|
- Can view only their own client area.
|
|
- Cannot create, edit, or delete content in the first version.
|
|
- Cannot access other clients.
|
|
|
|
## Authentication and Invitations
|
|
|
|
- The application must have a login screen.
|
|
- There must be no public registration screen.
|
|
- The super admin can create users and send email invitations.
|
|
- Invitations must use a unique token, expiration date, and single-use flow.
|
|
- Passwords must be stored with a strong hash, never as plaintext.
|
|
- Password reset, if implemented, must use temporary tokens.
|
|
- Sessions must expire and be revocable.
|
|
|
|
## Permissions Model
|
|
|
|
Use role-based access control with client scoping.
|
|
|
|
Minimum roles:
|
|
|
|
- `super_admin`
|
|
- `agency_user`
|
|
- `client_viewer`
|
|
|
|
Minimum rules:
|
|
|
|
- `super_admin` can access everything.
|
|
- `agency_user` can access only assigned clients unless explicitly elevated.
|
|
- `client_viewer` can access only their linked client.
|
|
- Every sensitive route must validate authentication, role, and client scope.
|
|
- Never rely on frontend-only access control.
|
|
|
|
## Core Modules
|
|
|
|
### Login
|
|
|
|
- Simple, secure, responsive screen.
|
|
- Fields: email and password.
|
|
- Error messages in Portuguese.
|
|
- Brute-force protection.
|
|
- Do not reveal whether an email exists.
|
|
|
|
### Weekly Dashboard
|
|
|
|
General view of the current week.
|
|
|
|
It should show:
|
|
|
|
- planned content and commitments for the week;
|
|
- pending items;
|
|
- completed items;
|
|
- relevant holidays and commemorative dates;
|
|
- filters by client, status, and owner;
|
|
- clear highlight for today.
|
|
|
|
### Client Calendar
|
|
|
|
The core product surface.
|
|
|
|
It should support:
|
|
|
|
- monthly view;
|
|
- weekly view;
|
|
- day detail view;
|
|
- Brazilian national holidays;
|
|
- Brazilian commemorative dates;
|
|
- client-specific custom dates;
|
|
- content/posts attached to a date;
|
|
- attachments such as images, files, and text;
|
|
- content status.
|
|
|
|
### Day Content
|
|
|
|
Each day can contain one or more items.
|
|
|
|
Suggested fields:
|
|
|
|
- title;
|
|
- description;
|
|
- content type;
|
|
- status;
|
|
- owner;
|
|
- client;
|
|
- date;
|
|
- optional time;
|
|
- copy/text;
|
|
- images and attachments;
|
|
- internal notes;
|
|
- client-visible notes;
|
|
- change history.
|
|
|
|
Suggested statuses:
|
|
|
|
- `rascunho`
|
|
- `planejado`
|
|
- `em_producao`
|
|
- `em_revisao`
|
|
- `aprovado`
|
|
- `publicado`
|
|
- `cancelado`
|
|
|
|
Keep status values compatible with Portuguese UI labels.
|
|
|
|
### Custom Dates
|
|
|
|
Allow custom dates globally or per client.
|
|
|
|
Examples:
|
|
|
|
- company anniversary;
|
|
- store anniversary;
|
|
- institutional date;
|
|
- recurring campaign;
|
|
- commercial milestone;
|
|
- internal event.
|
|
|
|
Suggested fields:
|
|
|
|
- name;
|
|
- description;
|
|
- date;
|
|
- annual recurrence flag;
|
|
- optional client;
|
|
- visibility;
|
|
- color or category.
|
|
|
|
### Clients
|
|
|
|
Each client has their own area.
|
|
|
|
Suggested fields:
|
|
|
|
- name;
|
|
- slug;
|
|
- status;
|
|
- contacts;
|
|
- linked users;
|
|
- calendar settings;
|
|
- custom dates;
|
|
- display preferences.
|
|
|
|
## Brazilian Calendar
|
|
|
|
The application must support:
|
|
|
|
- Brazilian national holidays;
|
|
- Brazilian commemorative dates;
|
|
- internal custom dates;
|
|
- client-specific custom dates.
|
|
|
|
Recommended implementation:
|
|
|
|
- keep an internal table/cache for holidays and commemorative dates;
|
|
- sync holidays by year from a configurable external provider;
|
|
- allow manual fallback if the external API fails;
|
|
- separate official holidays from non-official commemorative dates;
|
|
- allow administrative review of imported dates.
|
|
|
|
Provider decision:
|
|
|
|
- Initial provider: BrasilAPI.
|
|
- Regional holidays, municipal holidays, client-specific dates, and agency-specific commemorative dates will be added manually through the application.
|
|
- The backend must still use a provider abstraction so another provider can be added later without rewriting calendar features.
|
|
|
|
Providers considered:
|
|
|
|
- BrasilAPI: Brazilian public API with national holiday endpoints.
|
|
- Nager.Date: international public holiday API by country, with public endpoints that do not require an API key.
|
|
- Feriados API or feriados.dev: Brazil-focused services with national, state, and city coverage.
|
|
- Calendarific: international paid/freemium API with support for countries and regions.
|
|
|
|
Initial recommendation:
|
|
|
|
- implement a backend `CalendarProvider` abstraction;
|
|
- configure the provider through `CALENDAR_PROVIDER`, defaulting to `brasilapi`;
|
|
- persist provider results in the database;
|
|
- allow manual registration of commemorative dates;
|
|
- never depend on real-time external API availability to render the calendar.
|
|
|
|
Expected variables:
|
|
|
|
- `CALENDAR_PROVIDER`
|
|
- `CALENDAR_API_BASE_URL`
|
|
- `CALENDAR_API_KEY`
|
|
- `CALENDAR_CACHE_TTL_HOURS`
|
|
|
|
## Security
|
|
|
|
The project must strictly follow OWASP best practices.
|
|
|
|
Minimum requirements:
|
|
|
|
- validate and sanitize all inputs;
|
|
- protect against XSS;
|
|
- protect against CSRF where applicable;
|
|
- protect against SQL injection using parameterized queries or safe ORM patterns;
|
|
- enforce backend access control on all protected routes;
|
|
- use strong password hashing;
|
|
- use secure cookies if cookie-based sessions are used;
|
|
- use restrictive CORS;
|
|
- rate-limit login and sensitive routes;
|
|
- set HTTP security headers;
|
|
- avoid sensitive data in logs;
|
|
- handle uploads securely;
|
|
- limit file size;
|
|
- validate MIME type and extension;
|
|
- store attachments safely;
|
|
- audit administrative actions;
|
|
- use environment variables for secrets;
|
|
- never commit credentials.
|
|
|
|
OWASP references to consider during implementation:
|
|
|
|
- OWASP Top 10.
|
|
- OWASP ASVS.
|
|
- OWASP Cheat Sheet Series.
|
|
|
|
## Suggested Repository Structure
|
|
|
|
```text
|
|
.
|
|
|-- AGENT.md
|
|
|-- README.md
|
|
|-- docker-compose.yml
|
|
|-- .env.example
|
|
|-- .gitea
|
|
| `-- workflows
|
|
| `-- ci.yml
|
|
|-- frontend
|
|
| |-- Dockerfile
|
|
| |-- package.json
|
|
| |-- src
|
|
| | |-- app
|
|
| | |-- components
|
|
| | |-- features
|
|
| | |-- lib
|
|
| | |-- routes
|
|
| | `-- styles
|
|
| `-- public
|
|
|-- backend
|
|
| |-- Dockerfile
|
|
| |-- go.mod
|
|
| |-- cmd
|
|
| | `-- api
|
|
| | `-- main.go
|
|
| |-- internal
|
|
| | |-- auth
|
|
| | |-- calendar
|
|
| | |-- clients
|
|
| | |-- config
|
|
| | |-- content
|
|
| | |-- database
|
|
| | |-- mail
|
|
| | |-- users
|
|
| | `-- security
|
|
| `-- migrations
|
|
`-- docs
|
|
|-- architecture.md
|
|
|-- security.md
|
|
`-- api.md
|
|
```
|
|
|
|
## Database
|
|
|
|
Database decision: PostgreSQL.
|
|
|
|
PostgreSQL is the correct fit because the application is relational by nature: users, clients, permissions, invitations, calendar items, attachments, statuses, and audit logs all need strong consistency and queryable relationships.
|
|
|
|
Initial entities:
|
|
|
|
- users;
|
|
- clients;
|
|
- client_users;
|
|
- invitations;
|
|
- calendar_dates;
|
|
- holidays;
|
|
- commemorative_dates;
|
|
- calendar_items;
|
|
- calendar_item_attachments;
|
|
- audit_logs;
|
|
- sessions or refresh_tokens, depending on authentication strategy.
|
|
|
|
Use consistent timestamps:
|
|
|
|
- `created_at`
|
|
- `updated_at`
|
|
- `deleted_at` when soft delete is needed.
|
|
|
|
Timezone rules:
|
|
|
|
- handle dates and times carefully;
|
|
- use `America/Sao_Paulo` as the default operational timezone;
|
|
- store instants in UTC when time is involved;
|
|
- store calendar-only dates as `date`, not timestamp.
|
|
|
|
## Uploads and Attachments
|
|
|
|
Attachments are a critical security surface.
|
|
|
|
Requirements:
|
|
|
|
- limit file size;
|
|
- restrict allowed file types;
|
|
- validate actual file content;
|
|
- rename files in storage;
|
|
- avoid serving uploads directly from the same domain without protection;
|
|
- prevent execution of uploaded files;
|
|
- store metadata in the database;
|
|
- support logical deletion.
|
|
|
|
Expected variables:
|
|
|
|
- `UPLOAD_MAX_SIZE_MB`
|
|
- `UPLOAD_ALLOWED_MIME_TYPES`
|
|
- `STORAGE_DRIVER`
|
|
- `STORAGE_LOCAL_PATH`
|
|
- `STORAGE_S3_ENDPOINT`
|
|
- `STORAGE_S3_BUCKET`
|
|
- `STORAGE_S3_ACCESS_KEY`
|
|
- `STORAGE_S3_SECRET_KEY`
|
|
|
|
## Email
|
|
|
|
Used for invitations and possibly password reset.
|
|
|
|
Expected variables:
|
|
|
|
- `SMTP_HOST`
|
|
- `SMTP_PORT`
|
|
- `SMTP_USER`
|
|
- `SMTP_PASSWORD`
|
|
- `SMTP_FROM_EMAIL`
|
|
- `SMTP_FROM_NAME`
|
|
- `APP_PUBLIC_URL`
|
|
|
|
## Minimum Environment Variables
|
|
|
|
```env
|
|
APP_ENV=production
|
|
APP_PUBLIC_URL=https://app.example.com.br
|
|
APP_TIMEZONE=America/Sao_Paulo
|
|
|
|
SUPER_ADMIN_EMAIL=admin@example.com.br
|
|
SUPER_ADMIN_PASSWORD=change-me-secure-password
|
|
|
|
DATABASE_URL=postgres://user:change-me-secure-password@postgres:5432/mira?sslmode=disable
|
|
|
|
JWT_SECRET=change-me-with-a-long-random-secret
|
|
JWT_ACCESS_TOKEN_TTL_MINUTES=15
|
|
JWT_REFRESH_TOKEN_TTL_DAYS=7
|
|
|
|
CORS_ALLOWED_ORIGINS=https://app.example.com.br
|
|
|
|
CALENDAR_PROVIDER=brasilapi
|
|
CALENDAR_API_BASE_URL=https://brasilapi.com.br
|
|
CALENDAR_API_KEY=
|
|
CALENDAR_CACHE_TTL_HOURS=24
|
|
|
|
SMTP_HOST=smtp.example.com.br
|
|
SMTP_PORT=587
|
|
SMTP_USER=
|
|
SMTP_PASSWORD=
|
|
SMTP_FROM_EMAIL=no-reply@example.com.br
|
|
SMTP_FROM_NAME=Mira
|
|
|
|
UPLOAD_MAX_SIZE_MB=10
|
|
UPLOAD_ALLOWED_MIME_TYPES=image/jpeg,image/png,image/webp,application/pdf
|
|
STORAGE_DRIVER=local
|
|
STORAGE_LOCAL_PATH=/var/lib/mira/uploads
|
|
```
|
|
|
|
## Backend API
|
|
|
|
Standards:
|
|
|
|
- versioned routes under `/api/v1`;
|
|
- consistent JSON responses;
|
|
- errors in `pt-BR`;
|
|
- payload validation before business logic;
|
|
- authentication middleware;
|
|
- authorization middleware;
|
|
- rate limit middleware;
|
|
- security headers middleware;
|
|
- structured logs.
|
|
|
|
Suggested initial routes:
|
|
|
|
```text
|
|
POST /api/v1/auth/login
|
|
POST /api/v1/auth/logout
|
|
POST /api/v1/auth/refresh
|
|
|
|
GET /api/v1/me
|
|
|
|
GET /api/v1/clients
|
|
POST /api/v1/clients
|
|
GET /api/v1/clients/:clientId
|
|
PATCH /api/v1/clients/:clientId
|
|
|
|
GET /api/v1/calendar/week
|
|
GET /api/v1/clients/:clientId/calendar
|
|
GET /api/v1/clients/:clientId/calendar/days/:date
|
|
|
|
POST /api/v1/clients/:clientId/calendar-items
|
|
GET /api/v1/calendar-items/:itemId
|
|
PATCH /api/v1/calendar-items/:itemId
|
|
DELETE /api/v1/calendar-items/:itemId
|
|
|
|
POST /api/v1/calendar-items/:itemId/attachments
|
|
DELETE /api/v1/attachments/:attachmentId
|
|
|
|
GET /api/v1/calendar/holidays
|
|
POST /api/v1/commemorative-dates
|
|
PATCH /api/v1/commemorative-dates/:dateId
|
|
DELETE /api/v1/commemorative-dates/:dateId
|
|
|
|
GET /api/v1/users
|
|
POST /api/v1/users/invitations
|
|
POST /api/v1/invitations/:token/accept
|
|
```
|
|
|
|
## Frontend
|
|
|
|
Principles:
|
|
|
|
- mobile-first;
|
|
- dense, clear, operational screens;
|
|
- no landing page;
|
|
- first screen after login should be the weekly dashboard;
|
|
- calendar must be easy to navigate on mobile;
|
|
- use shadcn/ui consistently;
|
|
- keep visible UI text in `pt-BR`;
|
|
- do not rely on color alone to communicate status;
|
|
- support loading, error, empty, and success states.
|
|
|
|
Initial screens:
|
|
|
|
- login;
|
|
- weekly dashboard;
|
|
- client list;
|
|
- client calendar;
|
|
- day detail;
|
|
- calendar item detail/create/edit;
|
|
- users and invitations;
|
|
- custom date settings.
|
|
|
|
## Gitea CI/CD
|
|
|
|
Minimum pipeline:
|
|
|
|
- frontend lint;
|
|
- frontend tests;
|
|
- frontend build;
|
|
- backend lint/vet;
|
|
- backend tests;
|
|
- backend build;
|
|
- Docker image builds;
|
|
- vulnerability checks where possible.
|
|
|
|
Expected file:
|
|
|
|
- `.gitea/workflows/ci.yml`
|
|
|
|
## Docker and Portainer
|
|
|
|
Expected deliverables:
|
|
|
|
- `frontend/Dockerfile`
|
|
- `backend/Dockerfile`
|
|
- `docker-compose.yml`
|
|
- `.env.example`
|
|
|
|
Docker Compose should include:
|
|
|
|
- frontend;
|
|
- backend;
|
|
- PostgreSQL;
|
|
- database volume;
|
|
- local upload volume when `STORAGE_DRIVER=local`.
|
|
|
|
All configuration must come from environment variables to support Portainer-based operation.
|
|
|
|
## Testing
|
|
|
|
Backend:
|
|
|
|
- business rule unit tests;
|
|
- authorization tests;
|
|
- calendar tests;
|
|
- invitation tests;
|
|
- validation tests;
|
|
- upload tests.
|
|
|
|
Frontend:
|
|
|
|
- tests for critical components;
|
|
- calendar rendering tests;
|
|
- login flow tests;
|
|
- role-based visibility tests.
|
|
|
|
E2E, when possible:
|
|
|
|
- super admin login;
|
|
- client creation;
|
|
- user invitation;
|
|
- client read-only access;
|
|
- calendar item creation;
|
|
- weekly view.
|
|
|
|
## MVP Acceptance Criteria
|
|
|
|
The MVP must allow:
|
|
|
|
- login with the super admin loaded from environment variables;
|
|
- client creation;
|
|
- internal and client users created through invitations;
|
|
- role-based access control;
|
|
- clients to view only their own page;
|
|
- agency users to view all permitted clients;
|
|
- monthly calendar per client;
|
|
- general weekly dashboard;
|
|
- Brazilian national holiday display;
|
|
- custom date registration;
|
|
- content creation per day;
|
|
- attachment of allowed images or files;
|
|
- responsive mobile UI;
|
|
- Docker Compose deployment through Portainer;
|
|
- basic Gitea CI/CD pipeline.
|
|
|
|
## Out of Scope for the Initial MVP
|
|
|
|
These can be planned after the MVP:
|
|
|
|
- public registration;
|
|
- client editing permissions;
|
|
- formal approval workflows;
|
|
- direct Instagram, Facebook, TikTok, or LinkedIn integration;
|
|
- automated publishing;
|
|
- real-time comments;
|
|
- push notifications;
|
|
- full kanban board;
|
|
- complex subscription-based multi-tenancy.
|
|
|
|
## Implementation Principles
|
|
|
|
- Prioritize clarity and security.
|
|
- Keep frontend, backend, and infrastructure separated.
|
|
- Avoid hard coupling to a single calendar provider.
|
|
- Protect all backend routes.
|
|
- Log important administrative actions.
|
|
- Create reusable components only when there is a real need.
|
|
- Prefer clear names over premature abstractions.
|
|
- Document relevant technical decisions in `docs/architecture.md`.
|
|
- Never commit secrets.
|
|
|
|
## Calendar References
|
|
|
|
- [BrasilAPI](https://brasilapi.com.br/)
|
|
- [Nager.Date](https://date.nager.at/)
|
|
- [Feriados API](https://feriadosapi.com/docs)
|
|
- [feriados.dev](https://feriados.dev/documentacao)
|
|
- [Calendarific](https://calendarific.com/)
|